/**
 * 
 */
package com.module.hq.engine;

import com.dalonedrau.jogl.engine.Interactive;
import com.dalonedrau.pool.PooledStringBuilder;
import com.dalonedrau.pool.StringBuilderPool;
import com.dalonedrau.vectors.Vector3;
import com.module.hq.bus.globals.HQGlobals;
import com.module.hq.bus.globals.SpellConsts;
import com.rpg.base.Spells;
import com.rpg.base.flyweight.Spell;
import com.rpg.base.globals.SpellGlobals;

/**
 * @author Donald
 */
public final class HQSpells implements Spells<HQInteractiveObject, Spell> {
	/** the singeton instance of {@link HQSpells}. */
	private static HQSpells	instance;
	/**
	 * Gets the one and only instance of {@link HQSpells}.
	 * @return {@link HQSpells}
	 */
	public static HQSpells getInstance() {
		if (HQSpells.instance == null) {
			HQSpells.instance = new HQSpells();
		}
		return HQSpells.instance;
	}
	/** the list of spells, active and inactive. */
	private Spell[]	spells	= new Spell[HQGlobals.MAX_SPELLS];
	/**
	 * {@inheritDoc}
	 */
	@Override
	public Spell getSpell(final int spellId) {
		return spells[spellId];
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void addSpellOn(final int caster, final int spell) throws Exception {
		if (Interactive.getInstance().hasIO(caster)
				&& spell > 0) {
			HQInteractiveObject io =
					(HQInteractiveObject) Interactive.getInstance().getIO(
							caster);
			io.addSpellOn(spell);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean canPayMana(final int num, final float cost,
			final boolean playSound) throws Exception {
		boolean canPay = false;
		if (num >= 0) {
			if (spells[num].hasFlag(SpellGlobals.SPELLCAST_FLAG_NOMANA)) {
				canPay = true;
			} else {
				int casterId = spells[num].getCaster();
				if (Interactive.getInstance().hasIO(casterId)) {
					HQInteractiveObject caster =
							(HQInteractiveObject) Interactive.getInstance()
									.getIO(casterId);
					if (caster.hasIOFlag(HQGlobals.IO_01_PC)) {
						canPay = true;
					} else if (caster.hasIOFlag(HQGlobals.IO_03_NPC)) {
						canPay = true;
					}
				}
			}
		}
		return canPay;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSpellId(final char[] spell) {
		int id = -1;
		PooledStringBuilder sb =
				StringBuilderPool.getInstance().getStringBuilder();
		sb.append(spell);
		id = this.getSpellId(sb.toString());
		sb.returnToPool();
		return id;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSpellId(final String spell) {
		int id = -1;
		if (spell.equalsIgnoreCase("BALL_OF_FLAME")) {
			id = SpellConsts.SPELL_10_FIRE_BALL_OF_FLAME;
		} else if (spell.equalsIgnoreCase("FIRE_OF_WRATH")) {
			id = SpellConsts.SPELL_02_FIRE_FIRE_OF_WRATH;
		} else if (spell.equalsIgnoreCase("COURAGE")) {
			id = SpellConsts.SPELL_06_FIRE_COURAGE;
		} else if (spell.equalsIgnoreCase("HEAL_BODY")) {
			id = SpellConsts.SPELL_01_EARTH_HEAL_BODY;
		} else if (spell.equalsIgnoreCase("ROCK_SKIN")) {
			id = SpellConsts.SPELL_05_EARTH_ROCK_SKIN;
		} else if (spell.equalsIgnoreCase("PASS_THROUGH_ROCK")) {
			id = SpellConsts.SPELL_09_EARTH_PASS_THROUGH_ROCK;
		} else if (spell.equalsIgnoreCase("GENIE")) {
			id = SpellConsts.SPELL_08_AIR_GENIE;
		} else if (spell.equalsIgnoreCase("TEMPEST")) {
			id = SpellConsts.SPELL_04_AIR_TEMPEST;
		} else if (spell.equalsIgnoreCase("SWIFT_WIND")) {
			id = SpellConsts.SPELL_00_AIR_SWIFT_WIND;
		} else if (spell.equalsIgnoreCase("SLEEP")) {
			id = SpellConsts.SPELL_07_WATER_SLEEP;
		} else if (spell.equalsIgnoreCase("WATER_OF_HEALING")) {
			id = SpellConsts.SPELL_03_WATER_WATER_OF_HEALING;
		} else if (spell.equalsIgnoreCase("VEIL_OF_MIST")) {
			id = SpellConsts.SPELL_11_WATER_VEIL_OF_MIST;
		}
		return id;
	}
	/**
	 * Determines if a specific IO has a spell on it.
	 * @param ioid the IO's reference id
	 * @param spellType the type of spell
	 * @return true if the IO has the spell in effect; false otherwise
	 * @throws Exception if the IO doesn't exist
	 */
	public boolean hasSpellOn(final int ioid, final int spellType) 
	throws Exception {
		if (!Interactive.getInstance().hasIO(ioid)) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		if (Interactive.getInstance().getIO(ioid) == null) {
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("IO ref id ");
			sb.append(ioid);
			sb.append(" does not exist.");
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		boolean has = false;
		HQInteractiveObject io = 
			(HQInteractiveObject) Interactive.getInstance().getIO(ioid);
		for (int i = 0; i < io.getNumberOfSpellsOn(); i++) {
			Spell spell = getSpell(io.getSpellOn(i));
			if (spell.getType() == spellType) {
				has = true;
				break;
			}
		}
		return has;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getSpellOn(final HQInteractiveObject io,
			final int spellType) {
		int id = -1;
		if (io != null) {
			for (int i = 0; i < io.getNumberOfSpellsOn(); i++) {
				if (spells[io.getSpellOn(i)].getType() == spellType
						&& spells[io.getSpellOn(i)].exists()) {
					id = io.getSpellOn(i);
				}
			}
		}
		return id;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public String makeSpellName(final int type) throws Exception {
		String name = "";
		switch (type) {
		case SpellConsts.SPELL_00_FIRE_BALL_OF_FLAME:
			name = "BALL_OF_FLAME";
			break;
		case SpellConsts.SPELL_01_FIRE_FIRE_OF_WRATH:
			name = "FIRE_OF_WRATH";
			break;
		case SpellConsts.SPELL_02_FIRE_COURAGE:
			name = "COURAGE";
			break;
		case SpellConsts.SPELL_03_EARTH_HEAL_BODY:
			name = "HEAL_BODY";
			break;
		case SpellConsts.SPELL_04_EARTH_ROCK_SKIN:
			name = "ROCK_SKIN";
			break;
		case SpellConsts.SPELL_05_EARTH_PASS_THROUGH_ROCK:
			name = "PASS_THROUGH_ROCK";
			break;
		case SpellConsts.SPELL_06_AIR_GENIE:
			name = "GENIE";
			break;
		case SpellConsts.SPELL_07_AIR_TEMPEST:
			name = "TEMPEST";
			break;
		case SpellConsts.SPELL_08_AIR_SWIFT_WIND:
			name = "SWIFT_WIND";
			break;
		case SpellConsts.SPELL_09_WATER_SLEEP:
			name = "SLEEP";
			break;
		case SpellConsts.SPELL_10_WATER_WATER_OF_HEALING:
			name = "WATER_OF_HEALING";
			break;
		case SpellConsts.SPELL_11_WATER_VEIL_OF_MIST:
			name = "VEIL_OF_MIST";
			break;
		default:
			PooledStringBuilder sb =
					StringBuilderPool.getInstance().getStringBuilder();
			sb.append("Invalid spell type - ");
			sb.append(type);
			Exception ex = new Exception(sb.toString());
			sb.returnToPool();
			throw ex;
		}
		return name;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void manageMagic(final HQInteractiveObject io) {
		if (io != null) {
			if (io.hasIOFlag(HQGlobals.IO_01_PC)) {
				// check to see if PC is in combat
				// check to make sure controls aren't blocked
				// and PC isn't paralyzed

				HQCharacter pc = io.getPCData();
				if (HQPlayer.getInstance().isInFightMode(pc)) {
					// change player's animation to magic, and set
					// next animation to fighting stance
				}
				// if player is paralyzed, or unable to perform magic
				// remove magic animations
			}
		}
	}
	/**
	 * Notifies only the target of a spell that the spell has been cast.
	 * @param num the spell id.
	 * @throws Exception if an error occurs
	 */
	private void notifyOnlyTargetSpellCast(final int num) throws Exception {
		if (num >= 0
				&& num < HQGlobals.MAX_SPELLS
				&& spells[num].getTarget() >= 0
				&& Interactive.getInstance().hasIO(spells[num].getTarget())) {
			String spell = makeSpellName(spells[num].getType());
			int source = spells[num].getCaster();
			if (spell != null) {
				HQInteractiveObject ioSource = null;
				if (Interactive.getInstance().hasIO(source)) {
					ioSource =
							(HQInteractiveObject) Interactive
									.getInstance().getIO(source);
				}
				HQScript.getInstance().setEventSender(ioSource);
				String param = String.format("%s %f", spell,
						spells[num].getCasterLevel());
				// notify target that caster cast a spell
				HQScript.getInstance().sendIOScriptEvent(
						(HQInteractiveObject) Interactive.getInstance().getIO(
								spells[num].getTarget()),
						HQGlobals.SM_SPELLCAST,
						param,
						null
						);
			}
		}
	}
	/**
	 * Notifies the all interactive objects that a spell has been cast.
	 * @param num the spell id.
	 * @throws Exception if an error occurs
	 */
	private void notifySpellCast(final int num) throws Exception {
		if (num >= 0
				&& num < HQGlobals.MAX_SPELLS) {
			String spell = makeSpellName(spells[num].getType());
			int source = spells[num].getCaster();
			if (spell != null) {
				int ioNum = Interactive.getInstance().getNumberIOs();
				for (int i = 0; i < ioNum; i++) {
					if (Interactive.getInstance().hasIO(i)) {
						HQInteractiveObject io =
								(HQInteractiveObject) Interactive.getInstance()
										.getIO(i);
						HQInteractiveObject ioSource = null;
						if (Interactive.getInstance().hasIO(source)) {
							ioSource =
									(HQInteractiveObject) Interactive
											.getInstance().getIO(source);
						}
						HQScript.getInstance().setEventSender(ioSource);
						String param = String.format("%s %f", spell,
								spells[num].getCasterLevel());
						// notify all IOs that caster cast a spell
						HQScript.getInstance().sendIOScriptEvent(
								io,
								HQGlobals.SM_SPELLCAST,
								param,
								null
								);
					}
				}
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void analyze() {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void init() {
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			spells[i].setTimeToLive(0);
			spells[i].setTurnsToLive(0);
			spells[i].setExists(false);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void cancelAll() throws Exception {
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists()) {
				spells[i].setTimeToLive(0);
				spells[i].setTurnsToLive(0);		
			}
		}
		update();
		// remove all spells on the players
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject io =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
				if (io.hasIOFlag(HQGlobals.IO_01_PC)) {
					removeAllSpellsOn(io);
				}
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void clearAll() throws Exception {
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists()) {
				spells[i].setTimeToLive(0);
				spells[i].setTurnsToLive(0);
				spells[i].setExists(false);
			}
		}
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				HQInteractiveObject io =
						(HQInteractiveObject) Interactive.getInstance()
								.getIO(i);
					removeAllSpellsOn(io);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public int getFree() {
		int index = -1;
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (!spells[i].exists()) {
				index = i;
			}
		}
		return index;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean existAnyInstance(final int typ) {
		boolean exists = false;
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists() 
					&& spells[i].getType() == typ) {
				exists = true;
				break;
			}
		}
		return exists;
	}
	
	/**
	 * {@inheritDoc}
	 */
	@Override
	public long getInstance(final int typ) {
		int index = -1;
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists() 
					&& spells[i].getType() == typ) {
				index = i;
				break;
			}
		}
		return index;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public long getInstanceForThisCaster(final int typ, final int caster) {
		int index = -1;
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists() 
					&& spells[i].getType() == typ
					&& spells[i].getCaster() == caster) {
				index = i;
				break;
			}
		}
		return index;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean existAnyInstanceForThisCaster(final int typ, 
			final int caster) {
		boolean exists = false;
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists() 
					&& spells[i].getType() == typ
					&& spells[i].getCaster() == caster) {
				exists = true;
				break;
			}
		}
		return exists;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void abortSpellSound() {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void fizzle(final int num) {
		if (num < 0) {
			//ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE); // player fizzle
		} else {
			spells[num].setTimeToLive(0);
			spells[num].setTurnsToLive(0);
			// play a sound at casters position
			/*
			if (spells[num].caster >= 0)
				ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &spells[num].caster_pos);
				*/
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void fizzleAllSpellsFromCaster(final int casterId) {
		for (int i = 0; i < HQGlobals.MAX_SPELLS; i++) {
			if (spells[i].exists()
				&& spells[i].getCaster() == casterId) {
				spells[i].setTimeToLive(0);
				spells[i].setTurnsToLive(0);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void fizzleNoMana(final int num) {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void precastReset() {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void precastAdd(final long typ, final long level, final long flags, 
			final long duration) {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public long precastCheckCanPayMana(final long num, final float cost, 
			final boolean playSound) {
		// NOT USED
		return 0;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void precastCheck() {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void precastLaunch(final long num) {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public float getManaCost(long _lNumSpell, long lNumSpellTab) {
		// NOT USED
		return 0;
	}
	private void notify(final int num) {
		if (num < 0) return;

		if (num >= HQGlobals.MAX_SPELLS) return;

		String spell = makeSpellName(spells[num].getType());
		int source = spells[num].getCaster();

		if (spell != null) {
			for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
				if (HQInteractive.getInstance().hasIO(i)) {
					if (source >= 0) EVENT_SENDER = inter.iobj[source];
					else EVENT_SENDER = NULL;

					char param[256];
					sprintf(param,"%s %d",spell,(long)spells[num].caster_level);
					SendIOScriptEvent(inter.iobj[i], SM_SPELLCAST, param);
				}
			}	
		}	
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public long launchSpell(final int typ, final int source, final int flagss, 
			final int levell, final int target, final long timeDuration, 
			final int turnDuration) {
		long flags = flagss;
		long level = levell;
		int i;
		HQInteractiveObject ioSource = null;
		if (Interactive.getInstance().hasIO(source)) {
			ioSource =
					(HQInteractiveObject) Interactive.getInstance()
							.getIO(
									source);
		}
		float Player_Magic_Level = 0;

		if (ioSource != null
				&& ioSource.hasIOFlag(HQGlobals.IO_01_PC)) {
			resetRecognition();
			HQPlayer.getInstance().computePlayerFullStats(ioSource);			
		}
		// player casting spell
		// check spell type:
		switch (typ) {
		case HQGlobals.SPELL_02_FIRE_COURAGE:
		case HQGlobals.SPELL_03_EARTH_HEAL_BODY;
		case HQGlobals.SPELL_04_EARTH_ROCK_SKIN:
		case HQGlobals.SPELL_05_EARTH_PASS_THROUGH_ROCK:
		case HQGlobals.SPELL_08_AIR_SWIFT_WIND:
		case HQGlobals.SPELL_10_WATER_WATER_OF_HEALING:
		case HQGlobals.SPELL_11_WATER_VEIL_OF_MIST:
			// spell targeting a hero
			break;
		}

		if (target < 0
			&& ioSource != null
			&& ioSource.hasIOFlag(HQGlobals.IO_01_PC)) {
		switch (typ) {
			case SPELL_LOWER_ARMOR:
			case SPELL_CURSE:
			case SPELL_PARALYSE:				
			case SPELL_INCINERATE:			
			case SPELL_SLOW_DOWN:
			case SPELL_CONFUSE:
			{
					LOOKING_FOR_SPELL_TARGET_TIME	= ARXTimeUL();	
				LOOKING_FOR_SPELL_TARGET		= 1;
				t_spell.typ						= typ;
				t_spell.source					= source;
				t_spell.flags					= flags;
				t_spell.level					= level;
				t_spell.target					= target;
				t_spell.duration				= duration;
				return -1;
			}			
			case SPELL_ENCHANT_WEAPON:		
			{
					LOOKING_FOR_SPELL_TARGET_TIME	= ARXTimeUL();
				LOOKING_FOR_SPELL_TARGET		= 2;
				t_spell.typ						= typ;
				t_spell.source					= source;
				t_spell.flags					= flags;
				t_spell.level					= level;
				t_spell.target					= target;
				t_spell.duration				= duration;
				return -1;
			}	
			break;
			case SPELL_CONTROL_TARGET:
			{
				long		tcount = 0;
				EERIE_3D	cpos;

				if ( !ValidIONum( source ) )
					return -1;

				Vector_Copy( &cpos, &inter.iobj[source]->pos );

				for ( long ii = 1 ; ii < inter.nbmax ; ii++ )
				{
					INTERACTIVE_OBJ * ioo = inter.iobj[ii];

					if (	( ioo )
						&&	( ioo->ioflags & IO_NPC )
						&&	( ioo->_npcdata->life > 0.f )
						&&	( ioo->show == SHOW_FLAG_IN_SCENE )
						&&	( IsIOGroup( ioo, "DEMON") )	
						&&	( EEDistance3D(&ioo->pos,&cpos) < 900.f )
						)
					{
						tcount++;					
					}
				}

				if ( tcount == 0 ) 
				{
					ARX_SOUND_PlaySFX( SND_MAGIC_FIZZLE, &cpos );
					return -1;
				}

				ARX_SOUND_PlaySpeech( "Player_follower_attack" );
					LOOKING_FOR_SPELL_TARGET_TIME	= ARXTimeUL();
				LOOKING_FOR_SPELL_TARGET		= 1;
				t_spell.typ						= typ;
				t_spell.source					= source;
				t_spell.flags					= flags;
				t_spell.level					= level;
				t_spell.target					= target;
				t_spell.duration				= duration;
				return -1;
			}
			break;
		}
	}
		if ( source == 0 )
		{
			ARX_SPELLS_CancelSpellTarget();
		}


		// Try to create a new spell instance
		i = ARX_SPELLS_GetFree();

		if ( i < 0 )
		{
			return -1;
		}

		if ( source >= 0 && source < inter.nbmax )
		{
			if ( spellicons[typ].bAudibleAtStart )
			{
				ARX_NPC_SpawnAudibleSound(&inter.iobj[source]->pos,inter.iobj[source]);
			}
		}

		spells[i].caster = source;	// Caster...
		spells[i].target = target;	// No target if <0

		if ( target < 0 )
			spells[i].target = TemporaryGetSpellTarget( &inter.iobj[spells[i].caster]->pos );

		// Create hand position if a hand is defined
		if ( spells[i].caster == 0 ) 
		{
			spells[i].hand_group = inter.iobj[spells[i].caster]->obj->fastaccess.primary_attach;
		}
		else 
		{
			spells[i].hand_group = inter.iobj[spells[i].caster]->obj->fastaccess.left_attach;
		}

		if ( spells[i].hand_group != -1 )
		{
			spells[i].hand_pos.x = inter.iobj[spells[i].caster]->obj->vertexlist3[spells[i].hand_group].v.x;
			spells[i].hand_pos.y = inter.iobj[spells[i].caster]->obj->vertexlist3[spells[i].hand_group].v.y;
			spells[i].hand_pos.z = inter.iobj[spells[i].caster]->obj->vertexlist3[spells[i].hand_group].v.z;
		}

		if ( !source )
		{
			// Player source
			spells[i].caster_level = Player_Magic_Level;	// Level of caster

			spells[i].caster_pos.x = player.pos.x;
			spells[i].caster_pos.y = player.pos.y;
			spells[i].caster_pos.z = player.pos.z;

			spells[i].caster_angle.x = player.angle.x;
			spells[i].caster_angle.y = player.angle.y;
			spells[i].caster_angle.z = player.angle.z;		
			
		}
		else
		{
			// IO source
			spells[i].caster_level = level < 1 ? 1 : level > 10 ? 10 : ARX_CLEAN_WARN_CAST_FLOAT(level);

			spells[i].caster_pos.x = inter.iobj[source]->pos.x;
			spells[i].caster_pos.y = inter.iobj[source]->pos.y;
			spells[i].caster_pos.z = inter.iobj[source]->pos.z;

			spells[i].caster_angle.x = inter.iobj[source]->angle.x;
			spells[i].caster_angle.y = inter.iobj[source]->angle.y;
			spells[i].caster_angle.z = inter.iobj[source]->angle.z;		
		}

		if (flags & SPELLCAST_FLAG_LAUNCHPRECAST)
		{
			spells[i].caster_level = ARX_CLEAN_WARN_CAST_FLOAT(level);
		}

		// Checks target
		if (target<0) // no target... targeted by sight
		{
			if (source==0) // no target... player spell targeted by sight
			{
				spells[i].target_pos.x=player.pos.x-EEsin(DEG2RAD(player.angle.b))*60.f;
				spells[i].target_pos.y=player.pos.y+EEsin(DEG2RAD(player.angle.a))*60.f;
				spells[i].target_pos.z=player.pos.z+EEcos(DEG2RAD(player.angle.b))*60.f;

				spells[i].target_angle.a=0.f;
				spells[i].target_angle.b=0.f;
				spells[i].target_angle.g=0.f;
			}
			else
			{
				spells[i].target_pos.x=inter.iobj[target]->pos.x-EEsin(DEG2RAD(inter.iobj[target]->angle.b))*60.f;
				spells[i].target_pos.y=inter.iobj[target]->pos.y-120.f;
				spells[i].target_pos.z=inter.iobj[target]->pos.z+EEcos(DEG2RAD(inter.iobj[target]->angle.b))*60.f;

				spells[i].target_angle.a=0.f;
				spells[i].target_angle.b=0.f;
				spells[i].target_angle.g=0.f;
			}
		}
		// player target
		else if (target==0) 
		{
			spells[i].target_pos.x=player.pos.x;
			spells[i].target_pos.y=player.pos.x;
			spells[i].target_pos.z=player.pos.z;

			spells[i].target_angle.a=player.angle.a;
			spells[i].target_angle.b=player.angle.b;
			spells[i].target_angle.g=player.angle.g;
		}
		// IO target
		else 
		{
			spells[i].target_pos.x=inter.iobj[target]->pos.x;
			spells[i].target_pos.y=inter.iobj[target]->pos.y;
			spells[i].target_pos.z=inter.iobj[target]->pos.z;

			spells[i].target_angle.a=inter.iobj[target]->angle.a;
			spells[i].target_angle.b=inter.iobj[target]->angle.b;
			spells[i].target_angle.g=inter.iobj[target]->angle.g;				
		}			

		// spell direction
		spells[i].vector_dir.x=spells[i].target_pos.x-spells[i].caster_pos.x;
		spells[i].vector_dir.y=spells[i].target_pos.y-spells[i].caster_pos.y;
		spells[i].vector_dir.z=spells[i].target_pos.z-spells[i].caster_pos.z;
		float t=Vector_Magnitude(&spells[i].vector_dir);

		if (t<=0) t=0.0001f;

		t=1.f/t;
		spells[i].vector_dir.x*=t;
		spells[i].vector_dir.y*=t;
		spells[i].vector_dir.z*=t;

		spells[i].flags=flags;
		spells[i].cumul=0;
		spells[i].pSpellFx=NULL;
		spells[i].type = typ;
		spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();

		switch (typ)
		{
			//*********************************************************************************************
			// LEVEL 1 SPELLS -----------------------------------------------------------------------------
			case SPELL_MAGIC_SIGHT: // Launching MAGIC_SIGHT

				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist=TRUE;
				spells[i].fManaCostPerSecond=0.36f;
				spells[i].bDuration = true;

				if (duration>-1) spells[i].tolive=duration;
				else spells[i].tolive=6000000;

				SPELLCAST_Notify(i);
				ARX_SOUND_PlaySFX(SND_SPELL_VISION_START, &spells[i].caster_pos);

				if (spells[i].caster==0)
				{
					Project.improve = 1;
					spells[i].snd_loop = SND_SPELL_VISION_LOOP;
					ARX_SOUND_PlaySFX(spells[i].snd_loop, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				}

			break;
			//----------------------------------------------------------------------------------------------
			case SPELL_MAGIC_MISSILE: // Launching MAGIC_MISSILE
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist = TRUE;
				spells[i].tolive = 20000;
					
				CSpellFx *pCSpellFx = NULL;
				long number;

				if ( ( sp_max ) || ( cur_rf == 3 ) )

				{
					ARX_CHECK_LONG(spells[i].caster_level);   
					number = ARX_CLEAN_WARN_CAST_LONG( spells[i].caster_level );
				}

				else 
				{
							if ( spells[i].caster_level < 3 ) number = 1;
					else	if ( spells[i].caster_level < 5 ) number = 2;
					else	if ( spells[i].caster_level < 7 ) number = 3;
					else	if ( spells[i].caster_level < 9 ) number = 4;
					else	number=5;
				}

				pCSpellFx = new CMultiMagicMissile(GDevice,number);			

				if (pCSpellFx != NULL)
				{
					EERIE_3D source_position,vector;
					pCSpellFx->spellinstance=i;
					Vector_Init(&source_position);
					Vector_Init(&vector);
					pCSpellFx->SetDuration((unsigned long) (6000));
					pCSpellFx->Create(source_position, vector );				
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}				

				SPELLCAST_Notify(i);
			}
			break;
			//----------------------------------------------------------------------------------------------
			case SPELL_IGNIT:// Launching IGNIT
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				bool bLightInRadius = false;
						
				spells[i].exist = TRUE;
				spells[i].tolive = 20000;
						
				CSpellFx *pCSpellFx = NULL;
						
				pCSpellFx = new CIgnit();
				
				CIgnit *pIgnit=(CIgnit *)pCSpellFx;

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;

					if (spells[i].hand_group!=-1)
					{
						target.x=spells[i].hand_pos.x;
						target.y=spells[i].hand_pos.y;
						target.z=spells[i].hand_pos.z;
					}
					else
					{
						target.x=spells[i].caster_pos.x;
						target.y=spells[i].caster_pos.y-50.f;
						target.z=spells[i].caster_pos.z;
					}

					long id=GetFreeDynLight();

					if (id!=-1)
					{
						DynLight[id].exist		=	1;
						DynLight[id].intensity	=	1.8f;
						DynLight[id].fallend	=	450.f;
						DynLight[id].fallstart	=	380.f;
						DynLight[id].rgb.r		=	1.f;
						DynLight[id].rgb.g		=	0.75f;
						DynLight[id].rgb.b		=	0.5f;
						DynLight[id].pos.x		=	target.x;
						DynLight[id].pos.y		=	target.y;
						DynLight[id].pos.z		=	target.z;
						DynLight[id].duration	=	300;
					}

					
					float fPerimeter = 400.0f + spells[i].caster_level*30.0f;
					
					pIgnit->Create(&target, fPerimeter, 500);
					CheckForIgnition(&target,fPerimeter,1,1);

					for (long ii=0;ii<MAX_LIGHTS;ii++)
					{
						if (GLight[ii]==NULL) continue;

						if ( (GLight[ii]->extras & EXTRAS_EXTINGUISHABLE)
							&& ((spells[i].caster!=0) || 
								((spells[i].caster==0) && !(GLight[ii]->extras & EXTRAS_NO_IGNIT)))
							&&
							((GLight[ii]->extras & EXTRAS_SEMIDYNAMIC) 
								|| (GLight[ii]->extras & EXTRAS_SPAWNFIRE)
								|| (GLight[ii]->extras & EXTRAS_SPAWNSMOKE) )
							&& (!GLight[ii]->status))
						{
							float dist=EEDistance3D(&target,&GLight[ii]->pos);

							if (dist<=(pIgnit->GetPerimetre()))								
							{
									pIgnit->AddLight(ii);
									bLightInRadius = true;
								}
							}
						}

					for (long n=0;n<MAX_SPELLS;n++)
					{
						if (!spells[n].exist) continue;

						switch (spells[n].type)
						{
							case SPELL_FIREBALL:
							{							
								CSpellFx *pCSpellFX = spells[n].pSpellFx;

								if (pCSpellFX)
								{
									CFireBall *pCF = (CFireBall*) pCSpellFX;
							
								EERIE_SPHERE sphere;
								sphere.origin.x=pCF->eCurPos.x;
								sphere.origin.y=pCF->eCurPos.y;
								sphere.origin.z=pCF->eCurPos.z;
								sphere.radius=__max(spells[i].caster_level*2.f,12.f);

								if (EEDistance3D(&target,&sphere.origin)<pIgnit->GetPerimetre()+sphere.radius)
								{
										spells[n].caster_level += 1; 
								}
							}

							break;
						}
					}
					}
				}

				if (pCSpellFx)
				{
					spells[i].pSpellFx = pCSpellFx;
					CIgnit *pIgnit=(CIgnit *)pCSpellFx;
					spells[i].tolive = pIgnit->GetDuration();
				}

				SPELLCAST_Notify(i);
			}
			break;
			//---------------------------------------------------------------------------------------------
			case SPELL_DOUSE:// Launching DOUSE
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				bool bLightInRadius = false;
				spells[i].exist = TRUE;
				spells[i].tolive = 20000;
						
				CSpellFx *pCSpellFx = NULL;					
				pCSpellFx = new CDoze();
						
				CDoze *pDoze=(CDoze *)pCSpellFx;

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;

					if (spells[i].hand_group>=0)
					{
						target.x=spells[i].hand_pos.x;
						target.y=spells[i].hand_pos.y;
						target.z=spells[i].hand_pos.z;
					}
					else
					{
						target.x=spells[i].caster_pos.x;
						target.y=spells[i].caster_pos.y-50.f;
						target.z=spells[i].caster_pos.z;
					}
							
					float fPerimeter = 400.0f + spells[i].caster_level*30.0f;
					pDoze->CreateDoze(&target, fPerimeter, 500);						
					CheckForIgnition(&target,fPerimeter,0,1);		

					for (long ii=0;ii<MAX_LIGHTS;ii++)
					{
						if (GLight[ii]==NULL) continue;

						if ( (GLight[ii]->extras & EXTRAS_EXTINGUISHABLE)
							&&
							((GLight[ii]->extras & EXTRAS_SEMIDYNAMIC) 
								|| (GLight[ii]->extras & EXTRAS_SPAWNFIRE)
								|| (GLight[ii]->extras & EXTRAS_SPAWNSMOKE) )
								&& (GLight[ii]->status))
						{
							float dist=EEDistance3D(&target,&GLight[ii]->pos);

							if (dist <= (pDoze->GetPerimetre())) 
								{
									pDoze->AddLightDoze(ii);	
									bLightInRadius = true;
								}
							}
						}

					if ((CURRENT_TORCH) && (EEDistance3D(&target,&player.pos)<pDoze->GetPerimetre()))
					{
						ARX_PLAYER_ClickedOnTorch(CURRENT_TORCH);
					}

					for (long n=0;n<MAX_SPELLS;n++)
					{
						if (!spells[n].exist) continue;

						switch (spells[n].type)
						{
							case SPELL_FIREBALL:
							{							
								CSpellFx *pCSpellFX;
								pCSpellFX= spells[n].pSpellFx;

								if (pCSpellFX)
								{
									CFireBall *pCF = (CFireBall*) pCSpellFX;
							
								EERIE_SPHERE sphere;
								sphere.origin.x=pCF->eCurPos.x;
								sphere.origin.y=pCF->eCurPos.y;
								sphere.origin.z=pCF->eCurPos.z;
								sphere.radius=__max(spells[i].caster_level*2.f,12.f);

								if (EEDistance3D(&target,&sphere.origin)<pDoze->GetPerimetre()+sphere.radius)
								{
									spells[n].caster_level-=spells[i].caster_level;

									if (spells[n].caster_level<1)
										spells[n].tolive=0;
								}
							}

							break;
							case SPELL_FIRE_FIELD:
							{					
								EERIE_3D pos;

								if (GetSpellPosition(&pos,n))
								{
									if (EEDistance3D(&target,&pos)<pDoze->GetPerimetre()+200)
									{
										spells[n].caster_level-=spells[i].caster_level;

										if (spells[n].caster_level<1)
											spells[n].tolive=0;
									}
								}
							}
							break;
						}
					}

					}
				}

				if (pCSpellFx)
				{
					spells[i].pSpellFx = pCSpellFx;
					CDoze *pDoze=(CDoze *)pCSpellFx;
					spells[i].tolive = pDoze->GetDuration();
				}

				SPELLCAST_Notify(i);
			}
			break;
			//---------------------------------------------------------------------------------------------
			case SPELL_ACTIVATE_PORTAL:// Launching ACTIVATE_PORTAL
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				ARX_SOUND_PlayInterface(SND_SPELL_ACTIVATE_PORTAL);
				spells[i].exist = TRUE;
				spells[i].tolive = 20;
				SPELLCAST_Notify(i);
			}
			break;			
			//*************************************************************************************************
			// LEVEL 2 SPELLS -----------------------------------------------------------------------------
			case SPELL_HEAL:// Launching HEAL
			{		
			//	return No_MagicAllowed();
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlaySFX(SND_SPELL_HEALING, &spells[i].caster_pos);					

				spells[i].exist = TRUE;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.4f*spells[i].caster_level;

				if (duration>-1) spells[i].tolive=duration;
				else spells[i].tolive=3500;

				CSpellFx *pCSpellFx = NULL;
				pCSpellFx = new CHeal(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					pCSpellFx->Create();
					pCSpellFx->SetDuration(spells[i].tolive);
					
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify(i);
			}
			break;
			//---------------------------------------------------------------------------------------------
			case SPELL_DETECT_TRAP:// Launching DETECT_TRAP
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_DETECT_TRAP,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				if (spells[i].caster==0)
				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlayInterface(SND_SPELL_DETECT_TRAP);

				spells[i].snd_loop = SND_SPELL_DETECT_TRAP_LOOP;

				if (spells[i].caster==0)
				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlaySFX(spells[i].snd_loop, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);

				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 60000;
				spells[i].fManaCostPerSecond=0.4f;
				spells[i].bDuration = true;
				SPELLCAST_Notify(i);
			}
			break;
			//---------------------------------------------------------------------------------------------
			case SPELL_ARMOR:// Launching ARMOR
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long idx=ARX_SPELLS_GetSpellOn(inter.iobj[spells[i].target],SPELL_ARMOR);

				if (idx>=0)
				{
					spells[idx].tolive = 0;
				}
				
				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;						
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;						
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;						
				}

				if (spells[i].caster==0)
					spells[i].target=spells[i].caster;
				
				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_START, &spells[i].target_pos);

				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_LOOP, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
					
				spells[i].exist = TRUE;

				if (spells[i].caster==0)
					spells[i].tolive = 20000000;
				else
					spells[i].tolive = 20000;

				if (duration>-1) spells[i].tolive=duration;
				
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.2f*spells[i].caster_level;
					
				CSpellFx *pCSpellFx = NULL;
				pCSpellFx = new CArmor();				

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					CArmor *pArmor=(CArmor *)pCSpellFx;
					pArmor->Create(spells[i].tolive, 0);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pArmor->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//------------------------------------------------------------------------------------------------
			case SPELL_LOWER_ARMOR:// Launching LOWER_ARMOR
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long idx=ARX_SPELLS_GetSpellOn(inter.iobj[spells[i].target],SPELL_LOWER_ARMOR);

				if (idx>=0)
				{
					spells[idx].tolive = 0;
				}

				if (spells[i].target<0) return -1;

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
					
				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlaySFX(SND_SPELL_ARMOR_START, &spells[i].caster_pos);
					
				spells[i].exist = TRUE;

				if (spells[i].caster==0)
					spells[i].tolive = 20000000;
				else
					spells[i].tolive = 20000;

				if (duration>-1) spells[i].tolive=duration;

				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.2f*spells[i].caster_level;
					
				CSpellFx *pCSpellFx = NULL;				
				pCSpellFx = new CLowerArmor();

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					CLowerArmor *pLowerArmor=(CLowerArmor *)pCSpellFx;
					pLowerArmor->Create(spells[i].tolive, spells[i].target);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//------------------------------------------------------------------------------------------------
			case SPELL_HARM:// Launching HARM
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				if (!(spells[i].flags & SPELLCAST_FLAG_NOSOUND))
					ARX_SOUND_PlaySFX(SND_SPELL_HARM, &spells[i].caster_pos);

				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LIFE_DRAIN,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_MANA_DRAIN,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				spells[i].exist=TRUE;
				spells[i].tolive=6000000;
				
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.4f;

				spells[i].longinfo=ARX_DAMAGES_GetFree();

				if (spells[i].longinfo!=-1)
				{
					damages[spells[i].longinfo].radius=150.f;
					damages[spells[i].longinfo].damages=4.f;//2.f;
					damages[spells[i].longinfo].area=DAMAGE_FULL;
					damages[spells[i].longinfo].duration=100000000;
					damages[spells[i].longinfo].source=spells[i].caster;
					damages[spells[i].longinfo].flags=DAMAGE_FLAG_DONT_HURT_SOURCE | DAMAGE_FLAG_FOLLOW_SOURCE | DAMAGE_FLAG_ADD_VISUAL_FX;
					damages[spells[i].longinfo].type=DAMAGE_TYPE_FAKEFIRE | DAMAGE_TYPE_MAGICAL;
					damages[spells[i].longinfo].exist=TRUE;
				}

				spells[i].longinfo2=GetFreeDynLight();

				if (spells[i].longinfo2 != -1)
				{
					long id = spells[i].longinfo2;
					DynLight[id].exist = 1;
					DynLight[id].intensity = 2.3f;
					DynLight[id].fallend = 700.f;
					DynLight[id].fallstart = 500.f;
					DynLight[id].rgb.r = 1.0f;
					DynLight[id].rgb.g = 0.0f;
					DynLight[id].rgb.b = 0.0f;
					DynLight[id].pos.x = spells[i].caster_pos.x;
					DynLight[id].pos.y = spells[i].caster_pos.y;
					DynLight[id].pos.z = spells[i].caster_pos.z;
				}

				if (duration>-1) spells[i].tolive=duration;

				SPELLCAST_Notify(i);				
			}
			break;			
			//**********************************************************************************************
			// LEVEL 3 SPELLS -----------------------------------------------------------------------------
			case SPELL_SPEED:// Launching SPEED
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 2.f;
				ARX_SOUND_PlaySFX(SND_SPELL_SPEED_START, &spells[i].caster_pos);

				if (spells[i].caster==0)
				{			
					spells[i].target = spells[i].caster;
					spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_SPEED_LOOP, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				}
					
				spells[i].exist = TRUE;

				if (spells[i].caster==0)
					spells[i].tolive = 200000000;
				else
					spells[i].tolive = 20000;

				if (duration>-1) spells[i].tolive=duration;
				
				
				CSpellFx *pCSpellFx = NULL;
				
				pCSpellFx = new CSpeed();			
				CSpeed *pSpeed = (CSpeed *)pCSpellFx;

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					pSpeed->Create(spells[i].target, spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pSpeed->GetDuration();
				}

				SPELLCAST_Notify(i);
				ARX_SPELLS_AddSpellOn(spells[i].target,i);

				if ((spells[i].caster>=0) && (spells[i].target<inter.nbmax))
				{
					if (inter.iobj[spells[i].target])
						inter.iobj[spells[i].target]->speed_modif+=spells[i].caster_level*DIV10;
				}
			}
			break;
			
			//--------------------------------------------------------------------------------------------------
			case SPELL_DISPELL_ILLUSION:// Launching DISPELL_ILLUSION (REVEAL)
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_DISPELL_ILLUSION);
				spells[i].exist = TRUE;
				spells[i].tolive = 1000;
				SPELLCAST_Notify(i);

				for (long n=0;n<MAX_SPELLS;n++)
				{
					if (!spells[n].exist) continue;

					if (spells[n].target==spells[i].caster) continue;

					if (spells[n].caster_level>spells[i].caster_level) continue;

					switch (spells[n].type)
					{
						case SPELL_INVISIBILITY:
						{		
							if (ValidIONum(spells[n].target) && ValidIONum(spells[i].caster))
							{
								if (EEDistance3D(&inter.iobj[spells[n].target]->pos, &inter.iobj[spells[i].caster]->pos)
									<1000)
								{
									spells[n].tolive=0;
								}
							}

							break;
						}
					}
				}
			}
			break;
		
			//----------------------------------------------------------------------------------------------
			
			case SPELL_FIREBALL:// Launching FIREBALL
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 20000;
				
				CSpellFx *pCSpellFx = NULL;
				pCSpellFx = new CFireBall();

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;

					if (spells[i].caster!=0)
						spells[i].hand_group=-1;

					if (spells[i].hand_group>=0)
					{
						target.x=spells[i].hand_pos.x;
						target.y=spells[i].hand_pos.y;
						target.z=spells[i].hand_pos.z;
					}
					else
					{
						target.x=spells[i].caster_pos.x;
						target.y=spells[i].caster_pos.y;
						target.z=spells[i].caster_pos.z;

						if ((ValidIONum(spells[i].caster))
							&& (inter.iobj[spells[i].caster]->ioflags & IO_NPC))
						{
							target.x-=EEsin(DEG2RAD(inter.iobj[spells[i].caster]->angle.b))*30.f;
							target.y-=80.f;
							target.z+=EEcos(DEG2RAD(inter.iobj[spells[i].caster]->angle.b))*30.f;
						}
					}
				
					pCSpellFx->SetDuration((unsigned long) (6000));
					CFireBall * cf=(CFireBall *)pCSpellFx;

					if (spells[i].caster==0)
						cf->Create(target,MAKEANGLE(player.angle.b),player.angle.a,spells[i].caster_level);
					else
					{
						float angle;

						if ((spells[i].target>=0) && (spells[i].target<inter.nbmax) && inter.iobj[spells[i].target])
						{
							angle = 0;
						}
						else angle=0;

						EERIE_3D eCurPos;

						eCurPos.x = inter.iobj[spells[i].caster]->pos.x ;
						eCurPos.y = inter.iobj[spells[i].caster]->pos.y;
						eCurPos.z = inter.iobj[spells[i].caster]->pos.z ;

						if ((ValidIONum(spells[i].caster))
							&& (inter.iobj[spells[i].caster]->ioflags & IO_NPC))
						{
							eCurPos.y-=80.f;						
						}

						INTERACTIVE_OBJ * _io=inter.iobj[spells[i].caster];

						if (ValidIONum(_io->targetinfo))
						{
							EERIE_3D * p1=&eCurPos;
							EERIE_3D * p2=&inter.iobj[_io->targetinfo]->pos;
							angle=(RAD2DEG(GetAngle(p1->y,p1->z,p2->y,p2->z+TRUEDistance2D(p2->x,p2->z,p1->x,p1->z))));//alpha entre orgn et dest;				
						}

						cf->Create(target,MAKEANGLE(inter.iobj[spells[i].caster]->angle.b),angle,spells[i].caster_level);					
					}
				}

				if (pCSpellFx)
				{
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SOUND_PlaySFX(SND_SPELL_FIRE_LAUNCH, &spells[i].caster_pos);
				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_FIRE_WIND, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				SPELLCAST_Notify(i);
			}
			break;
			//-------------------------------------------------------------------------------------------------
			case SPELL_CREATE_FOOD:// Launching CREATE_FOOD
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_CREATE_FOOD, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 3500;

				if (duration>-1) spells[i].tolive=duration;
						
				CSpellFx *pCSpellFx = NULL;

				if ((spells[i].caster==0) || (spells[i].target==0))
					player.hunger=100;
			
				pCSpellFx = new CCreateFood(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					pCSpellFx->Create();
					pCSpellFx->SetDuration(spells[i].tolive);						
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify(i);
			}
			break;
			//----------------------------------------------------------------------------------------------
			case SPELL_ICE_PROJECTILE:// Launching ICE_PROJECTILE
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				ARX_SOUND_PlaySFX(SND_SPELL_ICE_PROJECTILE_LAUNCH, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 4200;
					
				CSpellFx *pCSpellFx = NULL;
					
				pCSpellFx = new CIceProjectile(GDevice);
					
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;

					if (spells[i].caster==0)
					{
						target.x = player.pos.x - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*150.0f;
						target.y = player.pos.y+160;
						target.z = player.pos.z + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*150.0f;
						CIceProjectile *pIP = (CIceProjectile*)pCSpellFx;
						pIP->Create(target, MAKEANGLE(player.angle.b), spells[i].caster_level);
					}
					else
					{
						target.x = inter.iobj[spells[i].caster]->pos.x - EEsin(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*150.0f;
						target.y = inter.iobj[spells[i].caster]->pos.y;
						target.z = inter.iobj[spells[i].caster]->pos.z + EEcos(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*150.0f;
						CIceProjectile *pIP = (CIceProjectile*)pCSpellFx;
						pIP->Create(target, MAKEANGLE(inter.iobj[spells[i].caster]->angle.b), spells[i].caster_level);
					}

					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify(i);
			}
			break;
			//***********************************************************************************************	
			// LEVEL 4 SPELLS -----------------------------------------------------------------------------
			case SPELL_BLESS:// Launching BLESS
			{
				if (ARX_SPELLS_ExistAnyInstance(typ)) 
				{
					return -1;
				}

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				if (spells[i].caster==0)
					spells[i].target=0;

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_BLESS,spells[i].target);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				ARX_SOUND_PlaySFX(SND_SPELL_BLESS);
				spells[i].exist = TRUE;
				spells[i].tolive = 2000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.5f*spells[i].caster_level*0.6666f;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx = NULL;
				
				pCSpellFx = new CBless(GDevice);

				
					
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x = inter.iobj[spells[i].caster]->pos.x;
					target.y = inter.iobj[spells[i].caster]->pos.y;
					target.z = inter.iobj[spells[i].caster]->pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(20000);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//-----------------------------------------------------------------------------------------------
			case SPELL_DISPELL_FIELD:// Launching DISPELL_FIELD
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;					

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				SPELLCAST_Notify(i);
				spells[i].tolive = 10;
				EERIE_3D target;
				target.x = inter.iobj[spells[i].caster]->pos.x;
				target.y = inter.iobj[spells[i].caster]->pos.y;
				target.z = inter.iobj[spells[i].caster]->pos.z;
				long valid=0;
				long dispelled=0;

				for (long n=0;n<MAX_SPELLS;n++)
				{
					if (!spells[n].exist) continue;

					switch (spells[n].type)
					{					
						case SPELL_CREATE_FIELD:
						{							
							CSpellFx *pCSpellFX = spells[n].pSpellFx;

							if (pCSpellFX)
							{
								CCreateField *pCreateField = (CCreateField *) pCSpellFX;
						
								EERIE_SPHERE sphere;
								sphere.origin.x=pCreateField->eSrc.x;
								sphere.origin.y=pCreateField->eSrc.y;
								sphere.origin.z=pCreateField->eSrc.z;
								sphere.radius=400.f;

								if ((spells[i].caster!=0) || (spells[n].caster==0))
								{
									if (EEDistance3D(&target,&sphere.origin)<sphere.radius)
									{
										valid++;

										if (spells[n].caster_level<=spells[i].caster_level)
										{
											spells[n].tolive=0;
											dispelled++;
										}
									}
								}
							}

							break;
						}
						case SPELL_FIRE_FIELD:
						{							
							CSpellFx *pCSpellFX = spells[n].pSpellFx;

							if (pCSpellFX)
							{
								CFireField *pFireField = (CFireField *) pCSpellFX;
						
								EERIE_SPHERE sphere;
								sphere.origin.x=pFireField->pos.x;
								sphere.origin.y=pFireField->pos.y;
								sphere.origin.z=pFireField->pos.z;
								sphere.radius=400.f;

								if (EEDistance3D(&target,&sphere.origin)<sphere.radius)
								{
									valid++;

									if (spells[n].caster_level<=spells[i].caster_level)
									{
										spells[n].tolive=0;
										dispelled++;
									}
								}
							}

							break;
						}
						case SPELL_ICE_FIELD:
						{							
							CSpellFx *pCSpellFX = spells[n].pSpellFx;

							if (pCSpellFX)
							{
								CIceField *pIceField = (CIceField *) pCSpellFX;
						
								EERIE_SPHERE sphere;
								sphere.origin.x=pIceField->eSrc.x;
								sphere.origin.y=pIceField->eSrc.y;
								sphere.origin.z=pIceField->eSrc.z;
								sphere.radius=400.f;

								if (EEDistance3D(&target,&sphere.origin)<sphere.radius)
								{
									valid++;

									if (spells[n].caster_level<=spells[i].caster_level)
									{
										spells[n].tolive=0;
										dispelled++;
									}
								}
							}

							break;
						}
					}
				}

				if (valid>dispelled)
				{
					ARX_SPEECH_AddSpeech(inter.iobj[0],"[player_not_skilled_enough]",PARAM_LOCALISED,ANIM_TALK_NEUTRAL,ARX_SPEECH_FLAG_NOTEXT);

					if (dispelled>0)
					{
						ARX_SOUND_PlaySFX(SND_SPELL_DISPELL_FIELD);
					}
				}
				else if (valid>0)
				{
					ARX_SOUND_PlaySFX(SND_SPELL_DISPELL_FIELD);
				}
				else
				{
					ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE, &spells[i].caster_pos);
				}
			}
			break;
			//-----------------------------------------------------------------------------------------------
			case SPELL_FIRE_PROTECTION:// Launching FIRE_PROTECTION
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long idx=ARX_SPELLS_GetSpellOn(inter.iobj[spells[i].target],SPELL_FIRE_PROTECTION);

				if (idx>=0)
				{
					spells[idx].tolive = 0;
				}
		
				ARX_SOUND_PlaySFX(SND_SPELL_FIRE_PROTECTION);
				
				if (duration>-1) spells[i].tolive=duration;

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_COLD_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
				
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 2000000;

				if (spells[i].caster==0)
					spells[i].target=0;
					
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.f;
				
				CSpellFx *pCSpellFx = NULL;
					
				pCSpellFx = new CFireProtection();
					
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;		
					CFireProtection *pFP=(CFireProtection *)pCSpellFx;
					pFP->Create(spells[i].tolive, spells[i].target);

					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//----------------------------------------------------------------------------------------------
			case SPELL_COLD_PROTECTION:// Launching COLD_PROTECTION
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long idx=ARX_SPELLS_GetSpellOn(inter.iobj[spells[i].target],SPELL_COLD_PROTECTION);

				if (idx>=0)
				{
					spells[idx].tolive = 0;
				}

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LOWER_ARMOR,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_FIRE_PROTECTION,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				ARX_SOUND_PlaySFX(SND_SPELL_COLD_PROTECTION_START);

				if (spells[i].caster==0)
					spells[i].target=0;

				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 2000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.f;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx =  new CColdProtection();

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;		
					CColdProtection *pCP= (CColdProtection *)pCSpellFx;
					pCP->Create(spells[i].tolive, spells[i].target);
				
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_COLD_PROTECTION_LOOP, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//----------------------------------------------------------------------------------------------
			case SPELL_TELEKINESIS:// Launching TELEKINESIS
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(SPELL_TELEKINESIS,spells[i].caster)) return -1;			

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist=TRUE;						
				spells[i].tolive=6000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.9f;

				if (duration>-1) spells[i].tolive=duration;

				if (spells[i].caster==0)
					Project.telekinesis=1;

				ARX_SOUND_PlaySFX(SND_SPELL_TELEKINESIS_START, &spells[i].caster_pos);
				SPELLCAST_Notify(i);
			}
			break;
			//-----------------------------------------------------------------------------------------------
			case SPELL_CURSE:// Launching CURSE
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_CURSE,spells[i].target);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
						
				ARX_SOUND_PlaySFX(SND_SPELL_CURSE, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 2000000;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx = NULL;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 0.5f*spells[i].caster_level;
						
				pCSpellFx = new CCurse(GDevice);
				
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x=spells[i].target_pos.x;
					target.y=spells[i].target_pos.y;

					if ((spells[i].target>=0) && (inter.iobj[spells[i].target]))
					{
						if (spells[i].target==0) target.y-=200.f;
						else target.y+=inter.iobj[spells[i].target]->physics.cyl.height-50.f;
					}

					target.z=spells[i].target_pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
			}
			break;
			//*********************************************************************
			// LEVEL 5 SPELLS -----------------------------------------------------------------------------
			case SPELL_RUNE_OF_GUARDING:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_RUNE_OF_GUARDING,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
				
				ARX_SOUND_PlaySFX(SND_SPELL_RUNE_OF_GUARDING);
				spells[i].exist = TRUE;
				spells[i].tolive = 99999999;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx  = new CRuneOfGuarding(GDevice);
						
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;				
					target.x = inter.iobj[spells[i].caster]->pos.x;
					target.y = inter.iobj[spells[i].caster]->pos.y;
					target.z = inter.iobj[spells[i].caster]->pos.z;
					pCSpellFx->Create(target, 0);
					pCSpellFx->SetDuration(spells[i].tolive);

					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_LEVITATE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LEVITATE,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
				
				ARX_SOUND_PlaySFX(SND_SPELL_LEVITATE_START);
				spells[i].exist = TRUE;
				spells[i].tolive = 2000000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.f;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx =  new CLevitate();
								
				if (pCSpellFx != NULL)
				{
					CLevitate *pLevitate=(CLevitate *)pCSpellFx;
					pCSpellFx->spellinstance=i;
					EERIE_3D target;

					if (	(spells[i].caster==0)
						||	(spells[i].target==0)	)
					{
						target.x=player.pos.x;
						target.y=player.pos.y+150.f;
						target.z=player.pos.z;
						spells[i].target = 0; 
						spells[i].tolive = 200000000;
						player.levitate=1;
					}
					else
					{
						target.x=inter.iobj[spells[i].target]->pos.x;
						target.y = inter.iobj[spells[i].target]->pos.y; 
						target.z=inter.iobj[spells[i].target]->pos.z;
					}

					pLevitate->Create(16,50.f,100.f,80.f,&target,spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);				
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_CURE_POISON:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				float cure=spells[i].caster_level*10;

				if (spells[i].caster==0) 
					spells[i].target=0; 

				if (spells[i].target==0) 
				{
					player.poison-=cure;

					if (player.poison<0.f) player.poison=0;

					ARX_SOUND_PlaySFX(SND_SPELL_CURE_POISON);
				}
				else
				{
					if (ValidIONum(spells[i].target))
					{
						INTERACTIVE_OBJ * io=inter.iobj[spells[i].target];

						if (io->ioflags & IO_NPC)
						{
							io->_npcdata->poisonned-=cure;

							if (io->_npcdata->poisonned<0) io->_npcdata->poisonned=0;
						}

						ARX_SOUND_PlaySFX(SND_SPELL_CURE_POISON,&io->pos);
					}
				}
				
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 3500;
						
				CSpellFx *pCSpellFx = new CCurePoison(GDevice);
								
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					pCSpellFx->Create();
					pCSpellFx->SetDuration(spells[i].tolive);

					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
					
				}

				SPELLCAST_Notify(i);				
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_REPEL_UNDEAD:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_REPEL_UNDEAD,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
				
				ARX_SOUND_PlaySFX(SND_SPELL_REPEL_UNDEAD);

				if (spells[i].caster==0)
					spells[i].target=0;

				if (spells[i].target==0)
					spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_REPEL_UNDEAD_LOOP, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);

				spells[i].exist = TRUE;
				spells[i].tolive = 20000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.f;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx =  new CRepelUndead(GDevice);
				
				if (pCSpellFx != NULL)
				{
					EERIE_3D target;
					target.x=player.pos.x;
					target.y=player.pos.y;
					target.z=player.pos.z;
					pCSpellFx->spellinstance=i;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify(i);	
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_POISON_PROJECTILE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_POISON_PROJECTILE_LAUNCH, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 900000000;
						
				CSpellFx *pCSpellFx = NULL;

				ARX_CHECK_LONG(spells[i].caster_level);   
				pCSpellFx = new CMultiPoisonProjectile( GDevice, __max( ARX_CLEAN_WARN_CAST_LONG( spells[i].caster_level ), 1 ) );


				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					Vector_Init(&target);					
					pCSpellFx->SetDuration((unsigned long) (8000));
					float ang;

					if (spells[i].caster==0) ang=player.angle.b;
					else ang=inter.iobj[spells[i].caster]->angle.b;

					pCSpellFx->Create(target, MAKEANGLE(ang));
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();				
				}

				SPELLCAST_Notify(i);			
			}
			break;
			//***************************************************************************
			// LEVEL 6 -----------------------------------------------------------------------------
			case SPELL_RISE_DEAD:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_RISE_DEAD,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}
				
				float beta;
				EERIE_3D target;

				if (spells[i].caster==0)
				{
					target.x=player.pos.x - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*300.f;
					target.y = player.pos.y + 170.f; 
					target.z=player.pos.z + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*300.f;
					beta=MAKEANGLE(player.angle.b);
					
				}
				else
				{
					if (inter.iobj[spells[i].caster]->ioflags & IO_NPC)
					{
						target.x=inter.iobj[spells[i].caster]->pos.x - EEsin(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*300.f;
						target.y = inter.iobj[spells[i].caster]->pos.y; 
						target.z=inter.iobj[spells[i].caster]->pos.z + EEcos(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*300.f;					
					}
					else
					{
						target.x=inter.iobj[spells[i].caster]->pos.x;
						target.y=inter.iobj[spells[i].caster]->pos.y;
						target.z=inter.iobj[spells[i].caster]->pos.z;					
					}

					beta=MAKEANGLE(inter.iobj[spells[i].caster]->angle.b);
				}

				if (!ARX_INTERACTIVE_ConvertToValidPosForIO(NULL, &target))
				{
					ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
					return -1;
				}

				Vector_Copy(&spells[i].target_pos,&target);
				ARX_SOUND_PlaySFX(SND_SPELL_RAISE_DEAD, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 2000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.2f;
				spells[i].longinfo=-1;

				if (duration>-1) spells[i].tolive=duration;

				CSpellFx *pCSpellFx = NULL;
						
				pCSpellFx = new CRiseDead(GDevice);
						
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;					
					{
						pCSpellFx->Create(target, beta);
						CRiseDead *pRiseDead = (CRiseDead*) pCSpellFx;
						pRiseDead->SetDuration(2000, 500, 1800);
						pRiseDead->SetColorBorder(0.5, 0.5, 0.5);
						pRiseDead->SetColorRays1(0.83f, 0.73f, 0.63f);
						pRiseDead->SetColorRays2(0,0,0);
						pRiseDead->SetColorRays1(0.5, 0.5, 0.5);
						pRiseDead->SetColorRays2(1, 0, 0);

						if (pRiseDead->lLightId == -1)
						{
							pRiseDead->lLightId = GetFreeDynLight();
						}

						if (pRiseDead->lLightId != -1)
						{
							long id=pRiseDead->lLightId;
							DynLight[id].exist=1;
							DynLight[id].intensity = 1.3f;
							DynLight[id].fallend=450.f;
							DynLight[id].fallstart=380.f;
							DynLight[id].rgb.r=0.0f;
							DynLight[id].rgb.g=0.0f;
							DynLight[id].rgb.b=0.0f;
							DynLight[id].pos.x = target.x;
							DynLight[id].pos.y = target.y - 100;
							DynLight[id].pos.z = target.z;
							DynLight[id].duration=200;
							DynLight[id].time_creation = ARXTimeUL();
						}

						spells[i].pSpellFx = pCSpellFx;
						spells[i].tolive = pCSpellFx->GetDuration();
					}
				}

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_PARALYSE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;			

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				ARX_SOUND_PlaySFX(SND_SPELL_PARALYSE, &spells[i].caster_pos);
				spells[i].exist = TRUE;
				spells[i].tolive = 5000;
				
				if (duration>-1) spells[i].tolive=duration;

				if (ValidIONum(spells[i].target))
				{
					if (	(spells[i].target==0)
						&& (spells[i].caster_level<=player.level)	)
					{
						float mul=player.resist_magic;

						if (rnd()*100.f<mul)
						{
							mul*=DIV200;
							mul=1.f-mul;

							if (mul<0.5f) mul=0.5f;

							spells[i].tolive=(long)(float)(spells[i].tolive*mul);
						}
					}
					else
					{
					INTERACTIVE_OBJ * ioo=inter.iobj[spells[i].target];

					if (ioo->ioflags & IO_NPC)
					{
						float mul=ioo->_npcdata->resist_magic;

						if (rnd()*100.f<mul)
						{
							mul*=DIV200;
							mul=1.f-mul;

							if (mul<0.5f) mul=0.5f;

							spells[i].tolive=(long)(float)(spells[i].tolive*mul);
						}
					}
					}
				}
						
				inter.iobj[spells[i].target]->ioflags |= IO_FREEZESCRIPT;
				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				ARX_NPC_Kill_Spell_Launch(inter.iobj[spells[i].target]);
				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_CREATE_FIELD:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				spells[i].exist = TRUE;

				if (flags & SPELLCAST_FLAG_RESTORE)
				{				
					if ((float)ARXTime-4000>0)
						spells[i].lastupdate = spells[i].timcreation = ARXTimeUL() - 4000;
					else
						spells[i].lastupdate = spells[i].timcreation=0;
				}
				else
					spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();

				spells[i].tolive = 800000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.2f;

				if (duration>-1) spells[i].tolive=duration;


				EERIE_3D target;

				if (spells[i].caster==0)
				{
					target.x = inter.iobj[0]->pos.x - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*250.f;
					target.y = inter.iobj[0]->pos.y;
					target.z = inter.iobj[0]->pos.z + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*250.f;
				}
				else			
				{
					if (ValidIONum(spells[i].caster))
					{
						INTERACTIVE_OBJ * io=inter.iobj[spells[i].caster];

						if (io->ioflags & IO_NPC)
						{
							target.x = io->pos.x - EEsin(DEG2RAD(MAKEANGLE(io->angle.b)))*250.f;
							target.y = io->pos.y;
							target.z = io->pos.z + EEcos(DEG2RAD(MAKEANGLE(io->angle.b)))*250.f;
						}
						else
						{
							target.x=io->pos.x;					
							target.y=io->pos.y;
							target.z=io->pos.z;
						}
					}
				}

				ARX_SOUND_PlaySFX(SND_SPELL_CREATE_FIELD, &target);

				CSpellFx * pCSpellFx  = new CCreateField(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					char tmptext[256];
					sprintf(tmptext,"%sGraph\\Obj3D\\Interactive\\Fix_inter\\blue_cube\\blue_cube.asl",Project.workingdir);
					INTERACTIVE_OBJ * io;
					io=AddFix(GDevice,tmptext,IO_IMMEDIATELOAD);

					if (io)
					{
						ARX_INTERACTIVE_HideGore(io);								
						RestoreInitialIOStatusOfIO(io);
						spells[i].longinfo=GetInterNum(io);
						io->scriptload=1;
						io->ioflags|=IO_NOSAVE;
						io->ioflags|=IO_FIELD;

						io->initpos.x=io->pos.x=target.x;
						io->initpos.y=io->pos.y=target.y;
						io->initpos.z=io->pos.z=target.z;
						MakeTemporaryIOIdent(io);						
						SendInitScriptEvent(io);

						CCreateField *pCreateField = (CCreateField *) pCSpellFx;
						
						pCreateField->Create(target, 0);

						pCreateField->SetDuration(spells[i].tolive);
						pCreateField->lLightId = GetFreeDynLight();

						if (pCreateField->lLightId != -1)
						{
							long id=pCreateField->lLightId;
							DynLight[id].exist=1;
							DynLight[id].intensity = 0.7f + 2.3f;
							DynLight[id].fallend = 500.f;
							DynLight[id].fallstart = 400.f;
							DynLight[id].rgb.r = 0.8f;
							DynLight[id].rgb.g = 0.0f;
							DynLight[id].rgb.b = 1.0f;
							DynLight[id].pos.x = pCreateField->eSrc.x;
							DynLight[id].pos.y = pCreateField->eSrc.y-150;
							DynLight[id].pos.z = pCreateField->eSrc.z;
						}

						spells[i].pSpellFx = pCSpellFx;
						spells[i].tolive = pCSpellFx->GetDuration();

						if (flags & SPELLCAST_FLAG_RESTORE)
						{
							pCreateField->Update(4000);
						}
					}
					else spells[i].tolive=0;
				}

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_DISARM_TRAP:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_DISARM_TRAP);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 1;

				CSpellFx *pCSpellFx = new CDisarmTrap(GDevice);
						
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x=player.pos.x;
					target.y=player.pos.y;
					target.z=player.pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
					
					SPELLCAST_Notify(i);

					for (long n=0;n<MAX_SPELLS;n++)
					{
						if (!spells[n].exist) continue;

						switch (spells[n].type)
						{					
							case SPELL_RUNE_OF_GUARDING:
							{							
								CSpellFx *pCSpellFX = spells[n].pSpellFx;

								if (pCSpellFX)
								{
									CRuneOfGuarding * crg=(CRuneOfGuarding *)pCSpellFX;
									EERIE_SPHERE sphere;
									sphere.origin.x=crg->eSrc.x;
									sphere.origin.y=crg->eSrc.y;
									sphere.origin.z=crg->eSrc.z;
									sphere.radius=400.f;

									if (EEDistance3D(&target,&sphere.origin)<sphere.radius)
									{
										spells[n].caster_level-=spells[i].caster_level;

										if (spells[n].caster_level<=0)
										{
											spells[n].tolive=0;
										}
									}
								}

								break;
							}
						}
					}
				}
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_SLOW_DOWN:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				bool bOk = true;

				INTERACTIVE_OBJ *io = inter.iobj[spells[i].target];

				for (int il=0; il<io->nb_spells_on; il++)
				{
					if (spells[io->spells_on[il]].type == SPELL_SLOW_DOWN)
					{
						bOk = false;
						spells[i].exist = false;
						return -1;
					}
				}

				if (bOk)
				{
					ARX_SOUND_PlaySFX(SND_SPELL_SLOW_DOWN, &spells[i].caster_pos);
					spells[i].exist = TRUE;

					if (spells[i].caster==0)
						spells[i].tolive = 10000000;
					else
						spells[i].tolive = 10000;

					if (duration>-1) spells[i].tolive=duration;

					spells[i].pSpellFx = NULL;
					spells[i].bDuration = true;
					spells[i].fManaCostPerSecond = 1.2f;
					
					CSpellFx *pCSpellFx = new CSlowDown(GDevice);
					
					if (pCSpellFx != NULL)
					{
						pCSpellFx->spellinstance=i;
						EERIE_3D target;
						target.x=spells[i].target_pos.x;
						target.y=spells[i].target_pos.y;
						target.z=spells[i].target_pos.z;
						pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
						pCSpellFx->SetDuration(spells[i].tolive);
						spells[i].pSpellFx = pCSpellFx;
						spells[i].tolive = pCSpellFx->GetDuration();
					}

					SPELLCAST_Notify(i);
					
					
					ARX_SPELLS_AddSpellOn(spells[i].target,i);

					if ((spells[i].target>=0) && (spells[i].target<inter.nbmax))
					{
						if (inter.iobj[spells[i].target])
						{
								inter.iobj[spells[i].target]->speed_modif -= spells[i].caster_level*DIV20;
						}
					}
				}
			}	
			break;
			//****************************************************************************************
			// LEVEL 7 SPELLS -----------------------------------------------------------------------------
			case SPELL_FLYING_EYE:
			{	
				if (eyeball.exist!=0) return -1;

				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				if (spells[i].caster==0)
					spells[i].target=0;

				if (spells[i].target!=0)
					return -1;

				ARX_SOUND_PlaySFX(SND_SPELL_EYEBALL_IN);
				spells[i].exist=TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive=1000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 3.2f;
				eyeball.exist=1;
				eyeball.pos.x=player.pos.x-(float)EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*200.f;
				eyeball.pos.y=player.pos.y+50.f;
				eyeball.pos.z=player.pos.z+(float)EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*200.f;
				eyeball.angle.a=player.angle.a;
				spells[i].v.y=eyeball.angle.b=player.angle.b;
				eyeball.angle.g=player.angle.g;
				long j;

				for (long n=0;n<12;n++)
				{
					j=ARX_PARTICLES_GetFree();

					if ((j!=-1) && (!ARXPausedTimer))
					{
						ParticleCount++;
						PARTICLE_DEF * pd=&particle[j];
						pd->exist=TRUE;
						pd->zdec=0;							
	 
						pd->ov.x=eyeball.pos.x+5.f-rnd()*10.f;
						pd->ov.y=eyeball.pos.y+5.f-rnd()*10.f;
						pd->ov.z=eyeball.pos.z+5.f-rnd()*10.f;
						pd->move.x=2.f-4.f*rnd();
						pd->move.y=2.f-4.f*rnd();
						pd->move.z=2.f-4.f*rnd();
						pd->siz=28.f;
						pd->tolive=2000+(unsigned long)(float)(rnd()*4000.f);
						pd->scale.x=12.f;
						pd->scale.y=12.f;
						pd->scale.z=12.f;
						pd->timcreation=spells[i].lastupdate;
						pd->tc=tc4;
						pd->special=FADE_IN_AND_OUT | ROTATING | MODULATE_ROTATION | DISSIPATING;
						pd->fparam=0.0000001f;
						pd->r=0.7f;
						pd->g=0.7f;
						pd->b=1.f;
					}
				}

				TRUE_PLAYER_MOUSELOOK_ON |= 1;	
				SLID_START=(float)ARXTime;
				bOldLookToggle=pMenuConfig->bMouseLookToggle;
				pMenuConfig->bMouseLookToggle=true;

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_FIRE_FIELD:
			{
				if ( !CanPayMana( i, ARX_SPELLS_GetManaCost( typ, i ) ) )
				{
					return -1;
				}

				if ( !GLOBAL_MAGIC_MODE )
				{
					return No_MagicAllowed();
				}
				
				long iCancel = ARX_SPELLS_GetInstanceForThisCaster( SPELL_FIRE_FIELD, spells[i].caster );
				
				if ( iCancel > -1 )
				{
					spells[iCancel].tolive = 0;
				}
						
				ARX_SOUND_PlaySFX( SND_SPELL_FIRE_FIELD_START );
				spells[i].exist					= TRUE;
				spells[i].tolive				= 100000;
				spells[i].bDuration				= true;
				spells[i].fManaCostPerSecond	= 2.8f;
				spells[i].longinfo2				= -1;
				
				
				if ( duration > -1 ) spells[i].tolive = duration;
				
				CSpellFx *pCSpellFx = new CFireField();

				if ( pCSpellFx != NULL )
				{
					pCSpellFx->spellinstance	= i;
					CFireField *pFireField		= (CFireField *)pCSpellFx;

					EERIE_3D target;

					if ( spells[i].caster == 0 )
					{					
						target.x = player.pos.x - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*250.f;
						target.y = player.pos.y + 170;
						target.z = player.pos.z + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*250.f;
					}
					else			
					{
						if ( ValidIONum( spells[i].caster ) )
						{
							INTERACTIVE_OBJ * io = inter.iobj[spells[i].caster];

							if ( io->ioflags & IO_NPC )
							{
								target.x = io->pos.x - EEsin( DEG2RAD( MAKEANGLE( io->angle.b ) ) ) * 250.f;
								target.y = io->pos.y;
								target.z = io->pos.z + EEcos( DEG2RAD( MAKEANGLE( io->angle.b ) ) ) * 250.f;
							}
							else
							{
								target.x = io->pos.x;					
								target.y = io->pos.y;
								target.z = io->pos.z;
							}
						}

						else
						{
							ARX_CHECK_NO_ENTRY();
							target.x = 0;					
							target.y = 0;
							target.z = 0;
						}


					}

					spells[i].longinfo = ARX_DAMAGES_GetFree();

					if ( spells[i].longinfo != -1 )
					{
						damages[spells[i].longinfo].radius  = 150.f;
						damages[spells[i].longinfo].damages = 10.f;
						damages[spells[i].longinfo].area	= DAMAGE_FULL;
						damages[spells[i].longinfo].duration= 100000000;
						damages[spells[i].longinfo].source	= spells[i].caster;
						damages[spells[i].longinfo].flags	= 0;
						damages[spells[i].longinfo].type	= DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_FIRE | DAMAGE_TYPE_FIELD;
						damages[spells[i].longinfo].exist	= TRUE;
						damages[spells[i].longinfo].pos.x	= target.x;
						damages[spells[i].longinfo].pos.y	= target.y;
						damages[spells[i].longinfo].pos.z	= target.z;
					}

					pFireField->Create( 200.f, &target, spells[i].tolive );

					spells[i].pSpellFx	= pCSpellFx;
					spells[i].tolive	= pFireField->GetDuration();
					spells[i].snd_loop	= ARX_SOUND_PlaySFX( SND_SPELL_FIRE_FIELD_LOOP, &target, 1.0F, ARX_SOUND_PLAY_LOOPED );
				}

				SPELLCAST_Notify( i );			
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_ICE_FIELD:
			{
				if ( !CanPayMana( i, ARX_SPELLS_GetManaCost( typ, i ) ) )
				{
					return -1;
				}

				if ( !GLOBAL_MAGIC_MODE )
				{
					return No_MagicAllowed();
				}
				
				long iCancel = ARX_SPELLS_GetInstanceForThisCaster( SPELL_ICE_FIELD, spells[i].caster );

				if ( iCancel > -1 )
				{
					spells[iCancel].tolive = 0;
				}
					
				ARX_SOUND_PlaySFX(SND_SPELL_ICE_FIELD);
				spells[i].exist			= TRUE;
				spells[i].lastupdate	= spells[i].timcreation = ARXTimeUL();
				spells[i].tolive		= 100000;
				spells[i].bDuration		= true;
				spells[i].fManaCostPerSecond = 2.8f;
				spells[i].longinfo2		=-1;

				if ( duration > -1 ) 
				{
					spells[i].tolive = duration;
				}

				CSpellFx *pCSpellFx = new CIceField( GDevice );
						
				if ( pCSpellFx != NULL )
				{
					pCSpellFx->spellinstance = i;
					EERIE_3D target;

					if ( spells[i].caster == 0 )						
					{
						target.x = player.pos.x - EEsin( DEG2RAD( MAKEANGLE( player.angle.b ) ) ) * 250.f;
						target.y = player.pos.y + 170;
						target.z = player.pos.z + EEcos( DEG2RAD( MAKEANGLE( player.angle.b ) ) ) * 250.f;
					}
					else			
					{
						if ( ValidIONum( spells[i].caster ) )
						{
							INTERACTIVE_OBJ * io = inter.iobj[spells[i].caster];

							if ( io->ioflags & IO_NPC )
							{
								target.x = io->pos.x - EEsin( DEG2RAD( MAKEANGLE( io->angle.b ) ) ) * 250.f;
								target.y = io->pos.y;
								target.z = io->pos.z + EEcos( DEG2RAD( MAKEANGLE( io->angle.b ) ) ) * 250.f;
							}
							else
							{
								target.x = io->pos.x;					
								target.y = io->pos.y;
								target.z = io->pos.z;
							}
						}

						else
						{
							ARX_CHECK_NO_ENTRY();
							target.x = 0;					
							target.y = 0;
							target.z = 0;
						}


					}

					spells[i].longinfo = ARX_DAMAGES_GetFree();

					if ( spells[i].longinfo != -1 )
					{
						damages[spells[i].longinfo].radius  = 150.f;
						damages[spells[i].longinfo].damages = 10.f;
						damages[spells[i].longinfo].area	= DAMAGE_FULL;
						damages[spells[i].longinfo].duration= 100000000;
						damages[spells[i].longinfo].source	= spells[i].caster;
						damages[spells[i].longinfo].flags	= 0;
						damages[spells[i].longinfo].type	= DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_COLD | DAMAGE_TYPE_FIELD;
						damages[spells[i].longinfo].exist	= TRUE;
						damages[spells[i].longinfo].pos.x	= target.x;
						damages[spells[i].longinfo].pos.y	= target.y;
						damages[spells[i].longinfo].pos.z	= target.z;
					}

					pCSpellFx->Create( target, MAKEANGLE( player.angle.b ) );
					pCSpellFx->SetDuration( spells[i].tolive );
					spells[i].pSpellFx	= pCSpellFx;
					spells[i].tolive	= pCSpellFx->GetDuration();
				}

				SPELLCAST_Notify( i );
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_LIGHTNING_STRIKE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist = TRUE;
					
				CSpellFx *pCSpellFx = new CLightning();
					
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					CLightning *pL = (CLightning*) pCSpellFx;
					EERIE_3D source, target;
					source.x = 0;
					source.y = 0;
					source.z = 0;
					target.x = 0;
					target.y = 0;
					target.z = -500;
					pL->Create(source, target, MAKEANGLE(player.angle.b));
					pL->SetDuration((long)(500*spells[i].caster_level));
					pL->lSrc = 0;
						
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_START, &spells[i].caster_pos);
				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_LOOP, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_CONFUSE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_CONFUSE);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.5f;

				if (duration>-1) spells[i].tolive=duration;	

				CSpellFx *pCSpellFx = new CConfuse(GDevice);			

				if (pCSpellFx)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x=player.pos.x;
					target.y=player.pos.y;
					target.z=player.pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

			
				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				long source = spells[i].caster;
				char spell[128];

				if (MakeSpellName(spell,spells[i].type))
				{
					if (ValidIONum(spells[i].target))				
					{
						if (source >= 0) 
							EVENT_SENDER = inter.iobj[source];
						else 
							EVENT_SENDER = NULL;

						char param[256];
						sprintf(param,"%s %d",spell,(long)spells[i].caster_level);
						SendIOScriptEvent(inter.iobj[spells[i].target], SM_SPELLCAST, param);
					}
				}	
			
			}	
			break;
			//*********************************************************************************
			// LEVEL 8 SPELLS -----------------------------------------------------------------------------
			case SPELL_INVISIBILITY:
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist=TRUE;
				spells[i].tolive=6000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 3.f;

				if (duration>-1) spells[i].tolive=duration;

				if (spells[i].caster==0)
					spells[i].target=0;

				inter.iobj[spells[i].target]->GameFlags|=GFLAG_INVISIBILITY;
				inter.iobj[spells[i].target]->invisibility=0.f;
				ARX_SOUND_PlaySFX(SND_SPELL_INVISIBILITY_START, &spells[i].caster_pos);
				SPELLCAST_Notify(i);				
				ARX_SPELLS_AddSpellOn(spells[i].target,i);
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_MANA_DRAIN:
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;
				
				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_LIFE_DRAIN,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_HARM,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist=TRUE;
				spells[i].tolive=6000000;					
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 2.f;
				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD, &spells[i].caster_pos, 1.2F, ARX_SOUND_PLAY_LOOPED);

				if (duration>-1) spells[i].tolive=duration;

				spells[i].longinfo=ARX_DAMAGES_GetFree();

				if (spells[i].longinfo!=-1)
				{
					damages[spells[i].longinfo].radius=150.f;
					damages[spells[i].longinfo].damages = 8.f;
					damages[spells[i].longinfo].area=DAMAGE_FULL;
					damages[spells[i].longinfo].duration=100000000;
					damages[spells[i].longinfo].source=spells[i].caster;
					damages[spells[i].longinfo].flags=DAMAGE_FLAG_DONT_HURT_SOURCE | DAMAGE_FLAG_FOLLOW_SOURCE | DAMAGE_FLAG_ADD_VISUAL_FX;
					damages[spells[i].longinfo].type=DAMAGE_TYPE_FAKEFIRE | DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_DRAIN_MANA;
					damages[spells[i].longinfo].exist=TRUE;
				}

				spells[i].longinfo2=GetFreeDynLight();

				if (spells[i].longinfo2 != -1)
				{
					long id = spells[i].longinfo2;
					DynLight[id].exist = 1;
					DynLight[id].intensity = 2.3f;
					DynLight[id].fallend = 700.f;
					DynLight[id].fallstart = 500.f;
					DynLight[id].rgb.r = 0.0f;
					DynLight[id].rgb.g = 0.0f;
					DynLight[id].rgb.b = 1.0f;
					DynLight[id].pos.x = spells[i].caster_pos.x;
					DynLight[id].pos.y = spells[i].caster_pos.y;
					DynLight[id].pos.z = spells[i].caster_pos.z;
					DynLight[id].duration=900;
				}

				SPELLCAST_Notify(i);				
			}
			break;
			//----------------------------------------------------------------------------
			case SPELL_EXPLOSION:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_EXPLOSION);
						
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 2000;
				
				spells[i].longinfo=ARX_DAMAGES_GetFree();
				EERIE_3D target;
				target.x=inter.iobj[spells[i].caster]->pos.x;
				target.y=inter.iobj[spells[i].caster]->pos.y-60.f;

				if (spells[i].caster==0)
						target.y+=120.f;

				target.z=inter.iobj[spells[i].caster]->pos.z;

				if (spells[i].longinfo!=-1)
				{
					damages[spells[i].longinfo].radius=350.f;
					damages[spells[i].longinfo].damages=10.f;
					damages[spells[i].longinfo].area = 0; 
					damages[spells[i].longinfo].duration=spells[i].tolive;
					damages[spells[i].longinfo].source=spells[i].caster;
					damages[spells[i].longinfo].flags=DAMAGE_FLAG_DONT_HURT_SOURCE | DAMAGE_FLAG_FOLLOW_SOURCE | DAMAGE_FLAG_ADD_VISUAL_FX;
					damages[spells[i].longinfo].type=DAMAGE_TYPE_FAKEFIRE | DAMAGE_TYPE_MAGICAL;
					damages[spells[i].longinfo].exist=TRUE;
					damages[spells[i].longinfo].pos.x=target.x;
					damages[spells[i].longinfo].pos.y=target.y;
					damages[spells[i].longinfo].pos.z=target.z;
				}

				spells[i].longinfo2=GetFreeDynLight();

				if (spells[i].longinfo2 != -1)
				{
					long id = spells[i].longinfo2;
					DynLight[id].exist = 1;
					DynLight[id].intensity = 2.3f;
					DynLight[id].fallend = 700.f;
					DynLight[id].fallstart = 500.f;
					DynLight[id].rgb.r = 0.1f+rnd()*DIV3;
					DynLight[id].rgb.g = 0.1f+rnd()*DIV3;
					DynLight[id].rgb.b = 0.8f+rnd()*DIV5;
					DynLight[id].pos.x = target.x;
					DynLight[id].pos.y = target.y;
					DynLight[id].pos.z = target.z;
					DynLight[id].duration=200;
				}

				AddQuakeFX(300,2000,400,1);

				for ( long i_angle = 0 ; i_angle < 360 ; i_angle += 12 )
				{
					for ( long j = -100 ; j < 100 ; j += 50 )
					{	
						long		lvl;
						float		rr,		r2;
						EERIE_3D	pos,	dir;

						F2L( ( rnd() * 9.f + 4.f ), &lvl );
						rr		=	DEG2RAD( i_angle );
						r2		=	DEG2RAD( (float) ( j + 100 ) * DIV200 * 360.f ); 
						pos.x	=	target.x - EEsin(rr) * 360.f;  
						pos.y	=	target.y;
						pos.z	=	target.z + EEcos(rr) * 360.f;  
						dir.x	=	pos.x - target.x;
						dir.y	=	0;
						dir.z	=	pos.z - target.z;
						TRUEVector_Normalize( &dir );
						dir.x	*=	60.f;
						dir.y	*=	60.f;
						dir.z	*=	60.f;

						EERIE_RGB	rgb; 
						rgb.r	=	0.1f + rnd() * DIV3;
						rgb.g	=	0.1f + rnd() * DIV3;
						rgb.b	=	0.8f + rnd() * DIV5;

						EERIE_3D posi;
						posi.x	=	target.x;
						posi.y	=	target.y + j * 2;
						posi.z	=	target.z;
						
						LaunchFireballBoom( &posi, 16, &dir, &rgb );
					}
				}



				ARX_SOUND_PlaySFX(SND_SPELL_FIRE_WIND);
				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_ENCHANT_WEAPON:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist = TRUE;
				spells[i].tolive = 20;
					
				SPELLCAST_NotifyOnlyTarget(i);
			}
			break;			
			//----------------------------------------------------------------------------
			case SPELL_LIFE_DRAIN:
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_HARM,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}

				iCancel = ARX_SPELLS_GetInstanceForThisCaster(SPELL_MANA_DRAIN,spells[i].caster);

				if (iCancel > -1)
				{
					spells[iCancel].tolive = 0;
				}				

				spells[i].exist=TRUE;
				spells[i].tolive=6000000;
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 12.f;

				if (duration>-1) spells[i].tolive=duration;

				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_MAGICAL_SHIELD, &spells[i].caster_pos, 0.8F, ARX_SOUND_PLAY_LOOPED);
				spells[i].longinfo=ARX_DAMAGES_GetFree();

				if (spells[i].longinfo!=-1)
				{
					long id=spells[i].longinfo;
					damages[id].radius=150.f;
					damages[id].damages=spells[i].caster_level*DIV10*.8f;
					damages[id].area = 0; 
					damages[id].duration=100000000;
					damages[id].source=spells[i].caster;
					damages[id].flags=DAMAGE_FLAG_DONT_HURT_SOURCE | DAMAGE_FLAG_FOLLOW_SOURCE | DAMAGE_FLAG_ADD_VISUAL_FX;
					damages[id].type=DAMAGE_TYPE_FAKEFIRE | DAMAGE_TYPE_MAGICAL | DAMAGE_TYPE_DRAIN_LIFE;
					damages[id].exist=TRUE;
				}

				spells[i].longinfo2=GetFreeDynLight();

				if (spells[i].longinfo2 != -1)
				{
					long id = spells[i].longinfo2;
					DynLight[id].exist = 1;
					DynLight[id].intensity = 2.3f;
					DynLight[id].fallend = 700.f;
					DynLight[id].fallstart = 500.f;
					DynLight[id].rgb.r = 1.0f;
					DynLight[id].rgb.g = 0.0f;
					DynLight[id].rgb.b = 0.0f;
					DynLight[id].pos.x = spells[i].caster_pos.x;
					DynLight[id].pos.y = spells[i].caster_pos.y;
					DynLight[id].pos.z = spells[i].caster_pos.z;
					DynLight[id].duration=900;
				}

				SPELLCAST_Notify(i);				
			}
			break;
			//*****************************************************************************************
			// LEVEL 9 SPELLS -----------------------------------------------------------------------------
			case SPELL_SUMMON_CREATURE:
			{
				if (spells[i].caster_level>=9)
				{
					if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;
				}
				else if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_SUMMON_CREATURE);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.9f;
				spells[i].longinfo=0;
				spells[i].longinfo2=0;

				if (duration>-1) 
					spells[i].tolive=duration;	
				else
					spells[i].tolive = 2000000;
				

				float beta;
				EERIE_3D target;

				if (spells[i].caster==0)
				{
					target.x=player.pos.x - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*300.f;
					target.y = player.pos.y + 170.f; 
					target.z=player.pos.z + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*300.f;
					beta=MAKEANGLE(player.angle.b);
					
				}
				else
				{
					if (inter.iobj[spells[i].caster]->ioflags & IO_NPC)
					{
						target.x=inter.iobj[spells[i].caster]->pos.x - EEsin(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*300.f;
						target.y = inter.iobj[spells[i].caster]->pos.y;
						target.z=inter.iobj[spells[i].caster]->pos.z + EEcos(DEG2RAD(MAKEANGLE(inter.iobj[spells[i].caster]->angle.b)))*300.f;					
					}
					else
					{
						target.x=inter.iobj[spells[i].caster]->pos.x;
						target.y=inter.iobj[spells[i].caster]->pos.y;
						target.z=inter.iobj[spells[i].caster]->pos.z;					
					}

					beta=MAKEANGLE(inter.iobj[spells[i].caster]->angle.b);
				}

				if (!ARX_INTERACTIVE_ConvertToValidPosForIO(NULL, &target))
				{
					spells[i].exist = false;
					ARX_SOUND_PlaySFX(SND_MAGIC_FIZZLE);
					return -1;
				}

				if ((spells[i].caster==0) && (cur_mega==10))
					spells[i].fdata=1.f;
				else
					spells[i].fdata=0.f;

				Vector_Copy(&spells[i].target_pos,&target);
				CSpellFx *pCSpellFx = new CSummonCreature(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					CSummonCreature *pSummon = (CSummonCreature*) pCSpellFx;
						
					pSummon->Create(target, MAKEANGLE(player.angle.b));
						pSummon->SetDuration(2000, 500, 1500);
						pSummon->SetColorBorder(1, 0, 0);
						pSummon->SetColorRays1(0.93f, 0.93f, 0.63f);
						pSummon->SetColorRays2(0,0,0);
						pSummon->SetColorRays1(1, 0, 0);
						pSummon->SetColorRays2(0.5f, 0.5f, 0);
						
						pCSpellFx->lLightId = GetFreeDynLight();

						if (pCSpellFx->lLightId > -1)
						{
							long id = pCSpellFx->lLightId;
							DynLight[id].exist = 1;
							DynLight[id].intensity = 0.3f;
							DynLight[id].fallend = 500.f;
							DynLight[id].fallstart = 400.f;
							DynLight[id].rgb.r = 1.0f;
							DynLight[id].rgb.g = 0.0f;
							DynLight[id].rgb.b = 0.0f;
							DynLight[id].pos.x = pSummon->eSrc.x;
							DynLight[id].pos.y = pSummon->eSrc.y;
							DynLight[id].pos.z = pSummon->eSrc.z;
						}

					spells[i].pSpellFx = pCSpellFx;
				}

				SPELLCAST_Notify(i);
			}	
			break;
			case SPELL_FAKE_SUMMON:
			{
				if (spells[i].caster_level>=9)
				{
					if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;
				}
				else if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (	(spells[i].caster<=0)
					||	(!ValidIONum(spells[i].target))		)
					return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				ARX_SOUND_PlaySFX(SND_SPELL_SUMMON_CREATURE);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 1.9f;

				if (duration>-1) 
					spells[i].tolive = 4000; 
				else
					spells[i].tolive = 4000;
				
				EERIE_3D target;
				
					target.x=inter.iobj[spells[i].target]->pos.x;
					target.y=inter.iobj[spells[i].target]->pos.y;
					target.z=inter.iobj[spells[i].target]->pos.z;					

					if (spells[i].target!=0)
					target.y-=170.f;
				
				
				Vector_Copy(&spells[i].target_pos,&target);
				CSpellFx *pCSpellFx = new CSummonCreature(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					CSummonCreature *pSummon = (CSummonCreature*) pCSpellFx;
						
					pSummon->Create(target, MAKEANGLE(player.angle.b));
					pSummon->SetDuration(2000, 500, 1500);
					pSummon->SetColorBorder(1, 0, 0);
					pSummon->SetColorRays1(0.93f, 0.93f, 0.63f);
					pSummon->SetColorRays2(0,0,0);
					pSummon->SetColorRays1(1, 0, 0);
					pSummon->SetColorRays2(0.5f, 0.5f, 0);
						
					pCSpellFx->lLightId = GetFreeDynLight();

					if (pCSpellFx->lLightId > -1)
					{
						long id = pCSpellFx->lLightId;
						DynLight[id].exist = 1;
						DynLight[id].intensity = 0.3f;
						DynLight[id].fallend = 500.f;
						DynLight[id].fallstart = 400.f;
						DynLight[id].rgb.r = 1.0f;
						DynLight[id].rgb.g = 0.0f;
						DynLight[id].rgb.b = 0.0f;
						DynLight[id].pos.x = pSummon->eSrc.x;
						DynLight[id].pos.y = pSummon->eSrc.y;
						DynLight[id].pos.z = pSummon->eSrc.z;
						
					}

					spells[i].pSpellFx = pCSpellFx;
				}

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_NEGATE_MAGIC:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_NEGATE_MAGIC);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 2.f;

				if (duration>-1) 
					spells[i].tolive=duration;	
				else
					spells[i].tolive = 1000000;

				CSpellFx *pCSpellFx = new CNegateMagic(GDevice);
				
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x=player.pos.x;
					target.y=player.pos.y;
					target.z=player.pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
				}

				if (spells[i].caster==0)
					spells[i].target=0;

				if (ValidIONum(spells[i].target))
					LaunchAntiMagicField(&inter.iobj[spells[i].target]->pos,i);

				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_INCINERATE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				INTERACTIVE_OBJ * tio=inter.iobj[spells[i].target];

				if	((tio->ioflags & IO_NPC) && (tio->_npcdata->life<=0.f))
					return -1;
				
				ARX_SOUND_PlaySFX(SND_SPELL_INCINERATE);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 20000;
				
				tio->sfx_flag|=SFX_TYPE_YLSIDE_DEATH;
				tio->sfx_flag|=SFX_TYPE_INCINERATE;
				tio->sfx_time = ARXTimeUL();
				ARX_SPELLS_AddSpellOn(spells[i].target,i);
				SPELLCAST_Notify(i);
				spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_FIREPLACE, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_MASS_PARALYSE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_MASS_PARALYSE);
				spells[i].exist = TRUE;

				if (duration>-1) 
					spells[i].tolive=duration;
				else
					spells[i].tolive = 10000;

				spells[i].longinfo2=0;

				for (long ii=0;ii<inter.nbmax;ii++)
				{
					INTERACTIVE_OBJ * tio=inter.iobj[ii];

					if (	(ii==spells[i].caster)
						||	(!tio)
						||	(!(tio->ioflags & IO_NPC))
						||	(tio->show!=SHOW_FLAG_IN_SCENE)
						||	(tio->ioflags & IO_FREEZESCRIPT)
						||	(EEDistance3D(&tio->pos,&inter.iobj[spells[i].caster]->pos)>500.f)	
						)
						continue;

					tio->ioflags |= IO_FREEZESCRIPT;
					ARX_NPC_Kill_Spell_Launch(tio);
					ARX_SPELLS_AddSpellOn(ii,i);
					spells[i].longinfo2++;
					spells[i].misc=realloc(spells[i].misc,sizeof(long)*spells[i].longinfo2);
					long * ptr=(long *)spells[i].misc;
					ptr[spells[i].longinfo2-1]=ii;
				}			

						SPELLCAST_Notify(i);
			}	
			break;
			//********************************************************************************************
			// LEVEL 10 SPELLS -----------------------------------------------------------------------------
			case SPELL_MASS_LIGHTNING_STRIKE:
			{	
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				for (long ii=0;ii<MAX_SPELLS;ii++) 
				{
					if ((spells[ii].exist) && (spells[ii].type==typ))
					{
						if (spells[ii].longinfo!=-1) 
							DynLight[spells[ii].longinfo].exist=0;

						spells[ii].longinfo=-1;
						spells[ii].tolive=0;
					}
				}
						
				spells[i].exist=TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive=5000;			
				spells[i].siz=0;
				spells[i].longinfo=GetFreeDynLight();

				if (spells[i].longinfo!=-1)
				{
					long id=spells[i].longinfo;
					DynLight[id].exist=1;
					DynLight[id].intensity=1.8f;
					DynLight[id].fallend=450.f;
					DynLight[id].fallstart=380.f;
					DynLight[id].rgb.r=1.f;
					DynLight[id].rgb.g=0.75f;
					DynLight[id].rgb.b=0.75f;
					DynLight[id].pos.x=spells[i].vsource.x;
					DynLight[id].pos.y=spells[i].vsource.y;
					DynLight[id].pos.z=spells[i].vsource.z;
				}

				CSpellFx *pCSpellFx = NULL;
						

				ARX_CHECK_LONG(spells[i].caster_level);   
				pCSpellFx = new CMassLightning( GDevice, __max( ARX_CLEAN_WARN_CAST_LONG( spells[i].caster_level ), 1 ) );

			
				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					float beta;

					if (spells[i].caster==0)
					{
						target.x=player.pos.x  - EEsin(DEG2RAD(MAKEANGLE(player.angle.b)))*500.f;
						target.y=player.pos.y  + 150.f;
						target.z=player.pos.z  + EEcos(DEG2RAD(MAKEANGLE(player.angle.b)))*500.f;
						beta=player.angle.b;
					}
					else
					{
						INTERACTIVE_OBJ * io=inter.iobj[spells[i].caster];
						target.x=io->pos.x  - EEsin(DEG2RAD(MAKEANGLE(io->angle.b)))*500.f;
						target.y=io->pos.y  - 20.f;
						target.z=io->pos.z  + EEcos(DEG2RAD(MAKEANGLE(io->angle.b)))*500.f;
						beta=io->angle.b;
					}

					pCSpellFx->SetDuration((long)(500*spells[i].caster_level));
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
				
					spells[i].pSpellFx = pCSpellFx;
					spells[i].tolive = pCSpellFx->GetDuration();
					spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_LOOP, &target, 1.0F, ARX_SOUND_PLAY_LOOPED);
				}
						
				ARX_SOUND_PlaySFX(SND_SPELL_LIGHTNING_START);
				SPELLCAST_Notify(i);
				// Draws White Flash on Screen
				GDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,  D3DBLEND_ONE);
				GDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND, D3DBLEND_ONE);												
				SETALPHABLEND(GDevice,TRUE);
				float val = 1.f; 

				EERIEDrawBitmap(GDevice,0.f,0.f,(float)DANAESIZX,(float)DANAESIZY,0.00009f,NULL,D3DRGB(0.5f+val*DIV2,val,val));
				SETALPHABLEND(GDevice,FALSE);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_CONTROL_TARGET:
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!ValidIONum(spells[i].target))
					return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				long tcount=0;
				INTERACTIVE_OBJ * tmp_io=inter.iobj[spells[i].target];

				for (long ii=1;ii<inter.nbmax;ii++)
				{
					INTERACTIVE_OBJ * ioo=inter.iobj[ii];

					if (	(ioo)
						&&	(ioo->ioflags & IO_NPC)
						&&	(ioo->_npcdata->life>0.f)
						&&	(ioo->show==SHOW_FLAG_IN_SCENE)
						&&	(IsIOGroup(ioo,"DEMON"))	
						&&	(EEDistance3D(&ioo->pos,&spells[i].caster_pos)<900.f)
						)
					{
						tcount++;
						char param[256];
						long n;
						F2L(spells[i].caster_level,&n);
						sprintf(param,"%s_%04d %d"
							,GetName(tmp_io->filename)
							,tmp_io->ident
							,n
							);
						
						SendIOScriptEvent(ioo,-1,param,"NPC_CONTROL");
					}
				}

				if (tcount==0) return -1;
				
				ARX_SOUND_PlaySFX(SND_SPELL_CONTROL_TARGET);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 1000;
				
				CSpellFx *pCSpellFx = NULL;
				pCSpellFx = new CControlTarget(GDevice);

				if (pCSpellFx != NULL)
				{
					pCSpellFx->spellinstance=i;
					EERIE_3D target;
					target.x=player.pos.x;
					target.y=player.pos.y;
					target.z=player.pos.z;
					pCSpellFx->Create(target, MAKEANGLE(player.angle.b));
					pCSpellFx->SetDuration(spells[i].tolive);
					spells[i].pSpellFx = pCSpellFx;
				}

				SPELLCAST_Notify(i);
			}	
			break;

			//----------------------------------------------------------------------------	
			case SPELL_FREEZE_TIME:
			{	
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				ARX_SOUND_PlaySFX(SND_SPELL_FREEZETIME);
				//ARX_TIME_Pause();
				spells[i].siz=spells[i].caster_level*0.08f;
				GLOBAL_SLOWDOWN -= spells[i].siz;
				
				spells[i].exist=TRUE;						
				spells[i].tolive=200000;		

				if (duration>-1) spells[i].tolive=duration;

				spells[i].bDuration = true;
				spells[i].fManaCostPerSecond = 30.f*spells[i].siz;
				spells[i].longinfo=(long)ARX_TIME_Get();
				SPELLCAST_Notify(i);
			}	
			break;
			//----------------------------------------------------------------------------
			case SPELL_MASS_INCINERATE:
			{
				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();
				
				ARX_SOUND_PlaySFX(SND_SPELL_MASS_INCINERATE);
				spells[i].exist = TRUE;
				spells[i].lastupdate = spells[i].timcreation = ARXTimeUL();
				spells[i].tolive = 20000;
				long nb_targets=0;

				for (long ii=0;ii<inter.nbmax;ii++)
				{
					INTERACTIVE_OBJ * tio=inter.iobj[ii];

					if (	(ii==spells[i].caster)
						||	(!tio)
						||	(!(tio->ioflags & IO_NPC))
						||	((tio->ioflags & IO_NPC) && (tio->_npcdata->life<=0.f))
						||	(tio->show!=SHOW_FLAG_IN_SCENE)
						||	(EEDistance3D(&tio->pos,&inter.iobj[spells[i].caster]->pos)>500.f)	)
						continue;

					tio->sfx_flag|=SFX_TYPE_YLSIDE_DEATH;
					tio->sfx_flag|=SFX_TYPE_INCINERATE;
					tio->sfx_time = ARXTimeUL();
					nb_targets++;
					ARX_SPELLS_AddSpellOn(ii,i);
				}			

				SPELLCAST_Notify(i);

				if (nb_targets)
					spells[i].snd_loop = ARX_SOUND_PlaySFX(SND_FIREPLACE, &spells[i].caster_pos, 1.0F, ARX_SOUND_PLAY_LOOPED);
				else
					spells[i].snd_loop = -1;
			}	
			break;			
			//----------------------------------------------------------------------------
			case SPELL_TELEPORT:
			{
				if (ARX_SPELLS_ExistAnyInstanceForThisCaster(typ,spells[i].caster)) return -1;

				if (!CanPayMana(i,ARX_SPELLS_GetManaCost(typ,i))) return -1;

				if (!GLOBAL_MAGIC_MODE)
					return No_MagicAllowed();

				spells[i].exist=TRUE;
				spells[i].tolive=7000;
				ARX_SOUND_PlaySFX(SND_SPELL_TELEPORT, &spells[i].caster_pos);

				if (spells[i].caster==0) LASTTELEPORT = 0.0F;

				SPELLCAST_Notify(i);
			}
			break;
		}

		return i;
	}
	/**
	 * Notifies the all interactive objects that a spell has ended.
	 * @param num the spell id.
	 * @throws Exception if an error occurs
	 */
	private void notifySpellEnd(final int num) throws Exception {
		if (num >= 0
				&& num < HQGlobals.MAX_SPELLS) {
			String spell = makeSpellName(spells[num].getType());
			if (spell != null) {
				int source = spells[num].getCaster();

				if (spells[num].getType() == SpellConsts.SPELL_09_WATER_SLEEP) {
					HQInteractiveObject ioSource = null;
					if (Interactive.getInstance().hasIO(source)) {
						ioSource =
								(HQInteractiveObject) Interactive.getInstance()
										.getIO(
												source);
					}
					HQScript.getInstance().setEventSender(ioSource);
					if (Interactive.getInstance()
							.hasIO(spells[num].getTarget())) {
						HQInteractiveObject ioTarget =
								(HQInteractiveObject) Interactive.getInstance()
										.getIO(
												spells[num].getTarget());
						String param = String.format("%s %f", spell,
								spells[num].getCasterLevel());
						HQScript.getInstance().sendIOScriptEvent(
								ioTarget,
								HQGlobals.SM_SPELLEND,
								param,
								null
								);
					}
				} else {
					int ioNum = Interactive.getInstance().getNumberIOs();
					for (int i = 0; i < ioNum; i++) {
						if (Interactive.getInstance().hasIO(i)) {
							HQInteractiveObject io =
									(HQInteractiveObject) Interactive
											.getInstance()
											.getIO(i);
							HQInteractiveObject ioSource = null;
							if (Interactive.getInstance().hasIO(source)) {
								ioSource =
										(HQInteractiveObject) Interactive
												.getInstance().getIO(source);
							}
							HQScript.getInstance().setEventSender(ioSource);
							String param = String.format("%s %f", spell,
									spells[num].getCasterLevel());
							// notify all IOs that spell ended
							HQScript.getInstance().sendIOScriptEvent(
									io,
									HQGlobals.SM_SPELLEND,
									param,
									null
									);
						}
					}
				}
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeAllSpellsOn(final HQInteractiveObject io) {
		io.removeAllSpells();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeMultiSpellOn(final int spell) throws Exception {
		for (int i = 0; i < Interactive.getInstance().getNumberIOs(); i++) {
			if (Interactive.getInstance().hasIO(i)) {
				removeSpellOn(i, spells[spell].getType());
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void removeSpellOn(final int caster, final int spell)
			throws Exception {
		if (Interactive.getInstance().hasIO(caster)
				&& spell > 0) {
			HQInteractiveObject io =
					(HQInteractiveObject) Interactive.getInstance().getIO(
							caster);
			io.removeSpellOn(spell);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void resetRecognition() {
		// NOT USED
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public boolean TemporaryGetSpellTarget(Vector3 from) {
		// NOT USED
		return false;
	}
}
